feat: Align with RVX [[v5.14.1-dev.1](https://github.com/inotia00/revanced-patches/releases/tag/v5.14.1-dev.1)]
This commit is contained in:
parent
91577930ed
commit
ab3f98cb31
60 changed files with 1594 additions and 413 deletions
|
|
@ -150,9 +150,15 @@ object YouTubeClient {
|
|||
* in the `Additional details` section.
|
||||
*/
|
||||
private val CLIENT_VERSION_ANDROID_VR = if (useAV1())
|
||||
"1.65.10"
|
||||
// Lowest version that supports AV1.
|
||||
// According to the changelog, only Quest 3 supports the AV1 codec in this version.
|
||||
// SABR is not used.
|
||||
// Cronet version: 122.0.6238.3
|
||||
"1.54.20"
|
||||
else
|
||||
"1.43.32" // Last version of minSdkVersion 24.
|
||||
// SABR is not used.
|
||||
// Cronet version: 113.0.5672.24
|
||||
"1.47.48"
|
||||
|
||||
/**
|
||||
* The device machine id for the Meta Quest 3, used to get opus codec with the Android VR client.
|
||||
|
|
@ -166,15 +172,15 @@ object YouTubeClient {
|
|||
private val OS_VERSION_ANDROID_VR = if (useAV1())
|
||||
"14"
|
||||
else
|
||||
"7.1.1"
|
||||
"10"
|
||||
private val ANDROID_SDK_VERSION_ANDROID_VR = if (useAV1())
|
||||
"34"
|
||||
else
|
||||
"25"
|
||||
"29"
|
||||
private val BUILD_ID_ANDROID_VR = if (useAV1())
|
||||
"UP1A.231005.007.A1"
|
||||
else
|
||||
"NGI77B"
|
||||
"QQ3A.200805.001"
|
||||
|
||||
private val USER_AGENT_ANDROID_VR = androidUserAgent(
|
||||
packageName = PACKAGE_NAME_ANDROID_VR,
|
||||
|
|
@ -327,6 +333,21 @@ object YouTubeClient {
|
|||
private const val CLIENT_VERSION_TVHTML5_EMBEDDED = "2.0"
|
||||
|
||||
|
||||
// WEB (Downgraded)
|
||||
/**
|
||||
* Same as WEB, but for some reason SABR is not applied.
|
||||
*
|
||||
* Available version
|
||||
* ===============
|
||||
* '1.20160315'
|
||||
* '1.20161001'
|
||||
* '1.20170222'
|
||||
*/
|
||||
private const val CLIENT_VERSION_WEB_LEGACY = "1.20160315"
|
||||
private const val USER_AGENT_WEB_LEGACY =
|
||||
"Mozilla/5.0 (X11; OpenBSD amd64; rv:45.0) Gecko/20100101 Firefox/45.0"
|
||||
|
||||
|
||||
// MWEB
|
||||
/**
|
||||
* Video not playable: Paid / Movie / Private / Age-restricted.
|
||||
|
|
@ -648,9 +669,9 @@ object YouTubeClient {
|
|||
|
||||
/**
|
||||
* PoToken client is currently not working.
|
||||
* Mobile Web has been temporarily removed from the available clients.
|
||||
* Mobile Web / Web has been temporarily removed from the available clients.
|
||||
*
|
||||
* TODO: Fix me when the SABR extractor is implemented in the future.
|
||||
* TODO: Content PoToken must be generated using the '/att/get' endpoint.
|
||||
*/
|
||||
MWEB(
|
||||
id = 2,
|
||||
|
|
@ -658,11 +679,31 @@ object YouTubeClient {
|
|||
userAgent = USER_AGENT_MWEB,
|
||||
requireJS = true,
|
||||
requirePoToken = true,
|
||||
// Android YouTube app does not support 'Cookie'.
|
||||
// Android YouTube app does not support 'Cookie'?.
|
||||
supportsCookies = false,
|
||||
refererFormat = CLIENT_REFERER_FORMAT_MWEB,
|
||||
clientName = "MWEB",
|
||||
friendlyName = "Mobile Web"
|
||||
),
|
||||
|
||||
/**
|
||||
* PoToken client is currently not working.
|
||||
* Mobile Web / Web has been temporarily removed from the available clients.
|
||||
*
|
||||
* TODO: Content PoToken must be generated using the '/att/get' endpoint.
|
||||
*/
|
||||
WEB_LEGACY(
|
||||
id = 1,
|
||||
clientVersion = CLIENT_VERSION_WEB_LEGACY,
|
||||
clientPlatform = CLIENT_PLATFORM_DESKTOP,
|
||||
userAgent = USER_AGENT_WEB_LEGACY,
|
||||
requireJS = true,
|
||||
requirePoToken = true,
|
||||
// Android YouTube app does not support 'Cookie'?.
|
||||
supportsCookies = false,
|
||||
refererFormat = CLIENT_REFERER_FORMAT_WEB,
|
||||
clientName = "WEB",
|
||||
friendlyName = "Web"
|
||||
);
|
||||
|
||||
companion object {
|
||||
|
|
@ -684,7 +725,6 @@ object YouTubeClient {
|
|||
TV,
|
||||
TV_SIMPLY_NO_POTOKEN,
|
||||
TV_LEGACY,
|
||||
//MWEB,
|
||||
ANDROID_VR_AUTH,
|
||||
IOS_DEPRECATED,
|
||||
)
|
||||
|
|
@ -697,7 +737,6 @@ object YouTubeClient {
|
|||
IPADOS,
|
||||
TV_SIMPLY_NO_POTOKEN,
|
||||
TV_LEGACY,
|
||||
//MWEB,
|
||||
ANDROID_VR_AUTH,
|
||||
IOS_DEPRECATED,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ object YouTubeVRClient {
|
|||
private const val PACKAGE_NAME_XR =
|
||||
"com.google.android.apps.youtube.xr"
|
||||
|
||||
private const val CLIENT_VERSION_OCULUS_1_43 = "1.43.32" // Last version of minSdkVersion 24.
|
||||
private const val CLIENT_VERSION_OCULUS_1_65 = "1.65.10"
|
||||
private const val CLIENT_VERSION_OCULUS_1_47 = "1.47.48"
|
||||
private const val CLIENT_VERSION_OCULUS_1_70 = "1.70.24"
|
||||
private const val CLIENT_VERSION_PICO = "1.64.34"
|
||||
private const val CLIENT_VERSION_XR = "1.69.27"
|
||||
|
||||
|
|
@ -30,6 +30,8 @@ object YouTubeVRClient {
|
|||
private const val DEVICE_MODEL_QUEST_PRO = "Quest Pro"
|
||||
|
||||
private const val OS_VERSION_HORIZON_OS_25 = "7.1.1"
|
||||
private const val OS_VERSION_HORIZON_OS_50 = "10"
|
||||
private const val OS_VERSION_HORIZON_OS_74 = "12"
|
||||
private const val OS_VERSION_HORIZON_OS_76 = "14"
|
||||
|
||||
private const val OS_VERSION_ONE_UI_XR = "14"
|
||||
|
|
@ -39,13 +41,15 @@ object YouTubeVRClient {
|
|||
private const val OS_VERSION_PICO_4 = "10"
|
||||
private const val OS_VERSION_PICO_4_ULTRA = "14"
|
||||
|
||||
private const val OS_VERSION_QUEST = OS_VERSION_HORIZON_OS_25
|
||||
private const val OS_VERSION_QUEST = OS_VERSION_HORIZON_OS_50
|
||||
private const val OS_VERSION_QUEST_2 = OS_VERSION_HORIZON_OS_76
|
||||
private const val OS_VERSION_QUEST_3 = OS_VERSION_HORIZON_OS_76
|
||||
private const val OS_VERSION_QUEST_3S = OS_VERSION_HORIZON_OS_76
|
||||
private const val OS_VERSION_QUEST_PRO = OS_VERSION_HORIZON_OS_76
|
||||
|
||||
private const val BUILD_ID_HORIZON_OS_25 = "NGI77B"
|
||||
private const val BUILD_ID_HORIZON_OS_50 = "QQ3A.200805.001"
|
||||
private const val BUILD_ID_HORIZON_OS_74 = "SQ3A.220605.009.A1"
|
||||
private const val BUILD_ID_HORIZON_OS_76 = "UP1A.231005.007.A1"
|
||||
|
||||
private const val BUILD_ID_ONE_UI_XR = "UML1.250710.002.A1"
|
||||
|
|
@ -56,7 +60,7 @@ object YouTubeVRClient {
|
|||
private const val BUILD_ID_PICO_4 = "5.13.3"
|
||||
private const val BUILD_ID_PICO_4_ULTRA = "UKQ1.240321.001"
|
||||
|
||||
private const val BUILD_ID_QUEST = BUILD_ID_HORIZON_OS_25
|
||||
private const val BUILD_ID_QUEST = BUILD_ID_HORIZON_OS_50
|
||||
private const val BUILD_ID_QUEST_2 = BUILD_ID_HORIZON_OS_76
|
||||
private const val BUILD_ID_QUEST_3 = BUILD_ID_HORIZON_OS_76
|
||||
private const val BUILD_ID_QUEST_3S = BUILD_ID_HORIZON_OS_76
|
||||
|
|
@ -81,35 +85,35 @@ object YouTubeVRClient {
|
|||
)
|
||||
|
||||
private val USER_AGENT_QUEST = oculusUserAgent(
|
||||
clientVersion = CLIENT_VERSION_OCULUS_1_43,
|
||||
clientVersion = CLIENT_VERSION_OCULUS_1_47,
|
||||
osVersion = OS_VERSION_QUEST,
|
||||
deviceModel = DEVICE_MODEL_QUEST,
|
||||
buildId = BUILD_ID_QUEST
|
||||
)
|
||||
|
||||
private val USER_AGENT_QUEST_2 = oculusUserAgent(
|
||||
clientVersion = CLIENT_VERSION_OCULUS_1_65,
|
||||
clientVersion = CLIENT_VERSION_OCULUS_1_70,
|
||||
osVersion = OS_VERSION_QUEST_2,
|
||||
deviceModel = DEVICE_MODEL_QUEST_2,
|
||||
buildId = BUILD_ID_QUEST_2
|
||||
)
|
||||
|
||||
private val USER_AGENT_QUEST_3 = oculusUserAgent(
|
||||
clientVersion = CLIENT_VERSION_OCULUS_1_65,
|
||||
clientVersion = CLIENT_VERSION_OCULUS_1_70,
|
||||
osVersion = OS_VERSION_QUEST_3,
|
||||
deviceModel = DEVICE_MODEL_QUEST_3,
|
||||
buildId = BUILD_ID_QUEST_3
|
||||
)
|
||||
|
||||
private val USER_AGENT_QUEST_3S = oculusUserAgent(
|
||||
clientVersion = CLIENT_VERSION_OCULUS_1_65,
|
||||
clientVersion = CLIENT_VERSION_OCULUS_1_70,
|
||||
osVersion = OS_VERSION_QUEST_3S,
|
||||
deviceModel = DEVICE_MODEL_QUEST_3S,
|
||||
buildId = BUILD_ID_QUEST_3S
|
||||
)
|
||||
|
||||
private val USER_AGENT_QUEST_PRO = oculusUserAgent(
|
||||
clientVersion = CLIENT_VERSION_OCULUS_1_65,
|
||||
clientVersion = CLIENT_VERSION_OCULUS_1_70,
|
||||
osVersion = OS_VERSION_QUEST_PRO,
|
||||
deviceModel = DEVICE_MODEL_QUEST_PRO,
|
||||
buildId = BUILD_ID_QUEST_PRO
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ package app.revanced.extension.shared.innertube.utils;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import app.revanced.extension.shared.utils.Logger;
|
||||
|
|
@ -19,7 +19,6 @@ public class AuthUtils {
|
|||
// Used to identify brand accounts.
|
||||
private static final String PAGE_ID_HEADER = "X-Goog-PageId";
|
||||
private static final String VISITOR_ID_HEADER = "X-Goog-Visitor-Id";
|
||||
private static final Map<String, String> REQUEST_HEADER = new LinkedHashMap<>(3);
|
||||
@NonNull
|
||||
private static String authorization = "";
|
||||
@NonNull
|
||||
|
|
@ -32,25 +31,21 @@ public class AuthUtils {
|
|||
* Injection point.
|
||||
*/
|
||||
public static void setRequestHeaders(String url, Map<String, String> requestHeaders) {
|
||||
if (requestHeaders == null) {
|
||||
return;
|
||||
}
|
||||
String newlyLoadedAuthorization = requestHeaders.get(AUTHORIZATION_HEADER);
|
||||
String newlyLoadedVisitorId = requestHeaders.get(VISITOR_ID_HEADER);
|
||||
boolean authorizationNeedsUpdating =
|
||||
StringUtils.isNotEmpty(newlyLoadedAuthorization) && !authorization.equals(newlyLoadedAuthorization);
|
||||
boolean visitorIdNeedsUpdating =
|
||||
StringUtils.isNotEmpty(newlyLoadedVisitorId) && !visitorId.equals(newlyLoadedVisitorId);
|
||||
if (!MapUtils.isEmpty(requestHeaders)) {
|
||||
String newlyLoadedAuthorization = requestHeaders.get(AUTHORIZATION_HEADER);
|
||||
String newlyLoadedVisitorId = requestHeaders.get(VISITOR_ID_HEADER);
|
||||
|
||||
if (authorizationNeedsUpdating && visitorIdNeedsUpdating) {
|
||||
REQUEST_HEADER.remove(AUTHORIZATION_HEADER);
|
||||
REQUEST_HEADER.remove(VISITOR_ID_HEADER);
|
||||
REQUEST_HEADER.put(AUTHORIZATION_HEADER, newlyLoadedAuthorization);
|
||||
REQUEST_HEADER.put(VISITOR_ID_HEADER, newlyLoadedVisitorId);
|
||||
authorization = newlyLoadedAuthorization;
|
||||
visitorId = newlyLoadedVisitorId;
|
||||
Logger.printDebug(() -> "new Authorization loaded: " + newlyLoadedAuthorization);
|
||||
Logger.printDebug(() -> "new VisitorId loaded: " + newlyLoadedVisitorId);
|
||||
if (StringUtils.isNotEmpty(newlyLoadedAuthorization) &&
|
||||
StringUtils.isNotEmpty(newlyLoadedVisitorId)) {
|
||||
if (!authorization.equals(newlyLoadedAuthorization)) {
|
||||
Logger.printDebug(() -> "new Authorization loaded: " + newlyLoadedAuthorization);
|
||||
}
|
||||
if (!visitorId.equals(newlyLoadedVisitorId)) {
|
||||
Logger.printDebug(() -> "new VisitorId loaded: " + newlyLoadedVisitorId);
|
||||
}
|
||||
authorization = newlyLoadedAuthorization;
|
||||
visitorId = newlyLoadedVisitorId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -60,11 +55,8 @@ public class AuthUtils {
|
|||
public static void setAccountIdentity(@Nullable String newlyLoadedPageId,
|
||||
boolean newlyLoadedIncognitoStatus) {
|
||||
if (StringUtils.isEmpty(newlyLoadedPageId)) {
|
||||
REQUEST_HEADER.remove(PAGE_ID_HEADER);
|
||||
pageId = "";
|
||||
} else if (!pageId.equals(newlyLoadedPageId)) {
|
||||
REQUEST_HEADER.remove(PAGE_ID_HEADER);
|
||||
REQUEST_HEADER.put(PAGE_ID_HEADER, newlyLoadedPageId);
|
||||
pageId = newlyLoadedPageId;
|
||||
Logger.printDebug(() -> "new PageId loaded: " + newlyLoadedPageId);
|
||||
}
|
||||
|
|
@ -72,7 +64,11 @@ public class AuthUtils {
|
|||
}
|
||||
|
||||
public static Map<String, String> getRequestHeader() {
|
||||
return REQUEST_HEADER;
|
||||
return new HashMap<>() {{
|
||||
put(AUTHORIZATION_HEADER, authorization);
|
||||
put(VISITOR_ID_HEADER, visitorId);
|
||||
put(PAGE_ID_HEADER, pageId);
|
||||
}};
|
||||
}
|
||||
|
||||
public static boolean isNotLoggedIn() {
|
||||
|
|
|
|||
|
|
@ -184,11 +184,11 @@ class StreamingDataRequest private constructor(
|
|||
if (value != null) {
|
||||
if (key == VISITOR_ID_HEADER) {
|
||||
if (!visitorData.isNullOrEmpty()) {
|
||||
finalRequestHeader.put(VISITOR_ID_HEADER, visitorData)
|
||||
finalRequestHeader[VISITOR_ID_HEADER] = visitorData
|
||||
continue
|
||||
}
|
||||
}
|
||||
finalRequestHeader.put(key, value)
|
||||
finalRequestHeader[key] = value
|
||||
}
|
||||
}
|
||||
return finalRequestHeader
|
||||
|
|
@ -201,13 +201,10 @@ class StreamingDataRequest private constructor(
|
|||
val value = requestHeader[key]
|
||||
if (value != null) {
|
||||
if (key == AUTHORIZATION_HEADER) {
|
||||
finalRequestHeader.put(
|
||||
AUTHORIZATION_HEADER,
|
||||
AuthPatch.getAuthorization()
|
||||
)
|
||||
finalRequestHeader[AUTHORIZATION_HEADER] = AuthPatch.getAuthorization()
|
||||
continue
|
||||
}
|
||||
finalRequestHeader.put(key, value)
|
||||
finalRequestHeader[key] = value
|
||||
}
|
||||
}
|
||||
return finalRequestHeader
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ public class PackageUtils extends Utils {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static boolean hasSystemFeature(String feature) {
|
||||
return getPackageManager().hasSystemFeature(feature);
|
||||
}
|
||||
|
||||
public static boolean isPackageEnabled(@NonNull String packageName) {
|
||||
ApplicationInfo applicationInfo = getApplicationInfo(packageName);
|
||||
if (applicationInfo != null) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import java.util.List;
|
|||
|
||||
import app.revanced.extension.shared.utils.Logger;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
import app.revanced.extension.youtube.utils.ExtendedUtils;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class AdsPatch {
|
||||
|
|
@ -57,6 +58,13 @@ public class AdsPatch {
|
|||
return HIDE_GET_PREMIUM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static boolean hideShortsAds(boolean original) {
|
||||
return HIDE_VIDEO_ADS || original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
|
|
@ -74,4 +82,17 @@ public class AdsPatch {
|
|||
return !HIDE_VIDEO_ADS && original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* <p>
|
||||
* Toolbar buttons (including the YouTube logo) and navigation bar buttons depend on the
|
||||
* '<a href="https://www.youtube.com/youtubei/v1/guide">'/guide' endpoint</a>' requests.
|
||||
* <p>
|
||||
* Therefore, the patch works if the 'osName' value is spoofed only in '/guide' endpoint requests.
|
||||
*
|
||||
* @return osName.
|
||||
*/
|
||||
public static String overrideOSName() {
|
||||
return ExtendedUtils.getOSName();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -652,7 +652,7 @@ public final class KeywordContentFilter extends Filter {
|
|||
}
|
||||
|
||||
return switch (selectedNavButton) {
|
||||
case HOME, EXPLORE -> hideHome;
|
||||
case HOME -> hideHome;
|
||||
case SUBSCRIPTIONS -> hideSubscriptions;
|
||||
// User is in the Library or notifications.
|
||||
default -> false;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package app.revanced.extension.youtube.patches.feed;
|
|||
|
||||
import static app.revanced.extension.shared.utils.Utils.hideViewBy0dpUnderCondition;
|
||||
import static app.revanced.extension.shared.utils.Utils.hideViewUnderCondition;
|
||||
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_20_10_OR_GREATER;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
@ -22,11 +23,59 @@ public class FeedPatch {
|
|||
return Settings.HIDE_CATEGORY_BAR_IN_FEED.get() ? 0 : height;
|
||||
}
|
||||
|
||||
public static boolean hideCategoryBarInRelatedVideos() {
|
||||
return Settings.HIDE_CATEGORY_BAR_IN_RELATED_VIDEOS.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to enforce a minimum height for subviews of the category bar.
|
||||
* This experimental flag was added in YouTube 20.10+ and must be true to hide the category bar without leaving any gaps.
|
||||
* Even if the experimental flag is removed in the future, this value will remain true.
|
||||
*/
|
||||
public static boolean hideCategoryBarInRelatedVideos(boolean original) {
|
||||
return hideCategoryBarInRelatedVideos() || original;
|
||||
}
|
||||
|
||||
public static void hideCategoryBarInRelatedVideos(final View chipView) {
|
||||
Utils.hideViewBy0dpUnderCondition(
|
||||
Settings.HIDE_CATEGORY_BAR_IN_RELATED_VIDEOS.get() || Settings.HIDE_RELATED_VIDEOS.get(),
|
||||
chipView
|
||||
);
|
||||
if (hideCategoryBarInRelatedVideos()) {
|
||||
// If the minimum height is 0, we can hide the view with setVisibility instead of changing LayoutParams.
|
||||
// Minimum height is only available in YouTube 20.10+.
|
||||
// In earlier versions, hide the view using LayoutParams.
|
||||
if (IS_20_10_OR_GREATER) {
|
||||
chipView.setVisibility(View.GONE);
|
||||
|
||||
// If you want to hide a View with LayoutParams, use the code enclosed in comments.
|
||||
|
||||
/*
|
||||
chipView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
|
||||
try {
|
||||
if (chipView instanceof ViewGroup viewGroup &&
|
||||
viewGroup.getParent() instanceof ViewGroup parentView) {
|
||||
if (parentView.getId() == ResourceUtils.getIdIdentifier("fullscreen_watch_next_chips") &&
|
||||
viewGroup.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||
Utils.hideViewGroupByMarginLayoutParams(viewGroup);
|
||||
} else {
|
||||
viewGroup.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "hideCategoryBarInRelatedVideos failed.", ex);
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
} else {
|
||||
Utils.hideViewByLayoutParams(chipView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum height to apply to subviews in the category bar.
|
||||
* This method is only available in YouTube 20.10+.
|
||||
*/
|
||||
public static int hideCategoryBarInRelatedVideos(final int height) {
|
||||
return hideCategoryBarInRelatedVideos() ? 0 : height;
|
||||
}
|
||||
|
||||
public static int hideCategoryBarInSearch(final int height) {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package app.revanced.extension.youtube.patches.general;
|
|||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton;
|
||||
|
||||
import android.view.View;
|
||||
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_AUTOMOTIVE;
|
||||
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_WATCH;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
|
|
@ -73,6 +73,47 @@ public class ChangeFormFactorPatch {
|
|||
private static final boolean USING_AUTOMOTIVE_TYPE = Objects.requireNonNull(
|
||||
FormFactor.AUTOMOTIVE.formFactorType).equals(FORM_FACTOR_TYPE);
|
||||
|
||||
private static final int smallestScreenWidthDp = PackageUtils.getSmallestScreenWidthDp();
|
||||
private static int clientFormFactorOrdinal = -1;
|
||||
|
||||
private static int getClientFormFactorOrdinal() {
|
||||
if (clientFormFactorOrdinal == -1) {
|
||||
if (IS_WATCH) {
|
||||
clientFormFactorOrdinal = 4; // WEARABLE_FORM_FACTOR
|
||||
} else if (IS_AUTOMOTIVE) {
|
||||
clientFormFactorOrdinal = 3; // AUTOMOTIVE_FORM_FACTOR
|
||||
} else {
|
||||
if (smallestScreenWidthDp >= 600) {
|
||||
clientFormFactorOrdinal = 2; // LARGE_FORM_FACTOR
|
||||
} else if (smallestScreenWidthDp > 0) {
|
||||
clientFormFactorOrdinal = 1; // SMALL_FORM_FACTOR
|
||||
} else {
|
||||
clientFormFactorOrdinal = 0; // UNKNOWN_FORM_FACTOR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clientFormFactorOrdinal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toolbar buttons (including the YouTube logo) and navigation bar buttons depend on the
|
||||
* '<a href="https://www.youtube.com/youtubei/v1/guide">'/guide' endpoint</a>' requests.
|
||||
* <p>
|
||||
* Therefore, the patch works if the 'clientFormFactor' value is spoofed only in '/guide' endpoint requests.
|
||||
*
|
||||
* @return clientFormFactor (ordinal).
|
||||
*/
|
||||
public static int getFormFactor() {
|
||||
int original = getClientFormFactorOrdinal();
|
||||
|
||||
return FORM_FACTOR_TYPE == null || USING_AUTOMOTIVE_TYPE
|
||||
// When 'USING_AUTOMOTIVE_TYPE' is true, the 'Shorts' button in the navigation bar is replaced with the 'Explore' button.
|
||||
// To prevent this, the original clientFormFactorOrdinal is used when 'USING_AUTOMOTIVE_TYPE' is true.
|
||||
? original
|
||||
: FORM_FACTOR_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
|
|
@ -117,7 +158,6 @@ public class ChangeFormFactorPatch {
|
|||
if (widthDp == null) {
|
||||
return original;
|
||||
}
|
||||
final int smallestScreenWidthDp = PackageUtils.getSmallestScreenWidthDp();
|
||||
if (smallestScreenWidthDp == 0) {
|
||||
return original;
|
||||
}
|
||||
|
|
@ -133,19 +173,4 @@ public class ChangeFormFactorPatch {
|
|||
public static boolean tabletLayoutEnabled() {
|
||||
return Objects.equals(FORM_FACTOR.formFactorType, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void navigationTabCreated(NavigationButton button, View tabView) {
|
||||
// On first startup of the app the navigation buttons are fetched and updated.
|
||||
// If the user immediately opens the 'You' or opens a video, then the call to
|
||||
// update the navigtation buttons will use the non automotive form factor
|
||||
// and the explore tab is missing.
|
||||
// Fixing this is not so simple because of the concurrent calls for the player and You tab.
|
||||
// For now, always hide the explore tab.
|
||||
if (USING_AUTOMOTIVE_TYPE && button == NavigationButton.EXPLORE) {
|
||||
tabView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import static app.revanced.extension.shared.utils.Utils.hideViewGroupByMarginLay
|
|||
import static app.revanced.extension.shared.utils.Utils.hideViewUnderCondition;
|
||||
import static app.revanced.extension.youtube.patches.utils.PatchStatus.ImageSearchButton;
|
||||
import static app.revanced.extension.youtube.patches.utils.PatchStatus.TargetActivityClass;
|
||||
import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
|
|
@ -26,17 +25,13 @@ import android.view.WindowManager;
|
|||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.apps.youtube.app.application.Shell_SettingsActivity;
|
||||
import com.google.android.apps.youtube.app.settings.SettingsActivity;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import app.revanced.extension.shared.utils.Logger;
|
||||
|
|
@ -203,71 +198,6 @@ public class GeneralPatch {
|
|||
|
||||
// endregion
|
||||
|
||||
// region [Hide navigation bar components] patch
|
||||
|
||||
private static final Map<NavigationButton, Boolean> shouldHideMap = new EnumMap<>(NavigationButton.class) {
|
||||
{
|
||||
put(NavigationButton.HOME, Settings.HIDE_NAVIGATION_HOME_BUTTON.get());
|
||||
put(NavigationButton.SHORTS, Settings.HIDE_NAVIGATION_SHORTS_BUTTON.get());
|
||||
put(NavigationButton.SUBSCRIPTIONS, Settings.HIDE_NAVIGATION_SUBSCRIPTIONS_BUTTON.get());
|
||||
put(NavigationButton.CREATE, Settings.HIDE_NAVIGATION_CREATE_BUTTON.get());
|
||||
put(NavigationButton.NOTIFICATIONS, Settings.HIDE_NAVIGATION_NOTIFICATIONS_BUTTON.get());
|
||||
put(NavigationButton.LIBRARY, Settings.HIDE_NAVIGATION_LIBRARY_BUTTON.get());
|
||||
}
|
||||
};
|
||||
|
||||
public static boolean enableNarrowNavigationButton(boolean original) {
|
||||
return Settings.ENABLE_NARROW_NAVIGATION_BUTTONS.get() || original;
|
||||
}
|
||||
|
||||
public static boolean enableTranslucentNavigationBar() {
|
||||
return Settings.ENABLE_TRANSLUCENT_NAVIGATION_BAR.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @noinspection ALL
|
||||
*/
|
||||
public static void setCairoNotificationFilledIcon(EnumMap enumMap, Enum tabActivityCairo) {
|
||||
final int fillBellCairoBlack = ResourceUtils.getDrawableIdentifier("yt_fill_bell_cairo_black_24");
|
||||
if (fillBellCairoBlack != 0) {
|
||||
// It's very unlikely, but Google might fix this issue someday.
|
||||
// If so, [fillBellCairoBlack] might already be in enumMap.
|
||||
// That's why 'EnumMap.putIfAbsent()' is used instead of 'EnumMap.put()'.
|
||||
enumMap.putIfAbsent(tabActivityCairo, Integer.valueOf(fillBellCairoBlack));
|
||||
}
|
||||
}
|
||||
|
||||
public static int getLibraryDrawableId(int original) {
|
||||
if (ExtendedUtils.IS_19_26_OR_GREATER &&
|
||||
!ExtendedUtils.isSpoofingToLessThan("19.27.00")) {
|
||||
int libraryCairoId = ResourceUtils.getDrawableIdentifier("yt_outline_library_cairo_black_24");
|
||||
if (libraryCairoId != 0) {
|
||||
return libraryCairoId;
|
||||
}
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
public static boolean switchCreateWithNotificationButton(boolean original) {
|
||||
return Settings.SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON.get() || original;
|
||||
}
|
||||
|
||||
public static void navigationTabCreated(NavigationButton button, View tabView) {
|
||||
if (BooleanUtils.isTrue(shouldHideMap.get(button))) {
|
||||
tabView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public static void hideNavigationLabel(TextView view) {
|
||||
hideViewUnderCondition(Settings.HIDE_NAVIGATION_LABEL.get(), view);
|
||||
}
|
||||
|
||||
public static void hideNavigationBar(View view) {
|
||||
hideViewUnderCondition(Settings.HIDE_NAVIGATION_BAR.get(), view);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region [Remove viewer discretion dialog] patch
|
||||
|
||||
/**
|
||||
|
|
@ -519,6 +449,21 @@ public class GeneralPatch {
|
|||
hideViewUnderCondition(isNotificationButton(enumString), view);
|
||||
}
|
||||
|
||||
public static void hideSearchButton(String enumString, View view) {
|
||||
if (!Settings.HIDE_TOOLBAR_SEARCH_BUTTON.get())
|
||||
return;
|
||||
|
||||
hideViewUnderCondition(isSearchButton(enumString), view);
|
||||
}
|
||||
|
||||
public static void hideSearchButton(MenuItem menuItem, int original) {
|
||||
menuItem.setShowAsAction(
|
||||
Settings.HIDE_TOOLBAR_SEARCH_BUTTON.get()
|
||||
? MenuItem.SHOW_AS_ACTION_NEVER
|
||||
: original
|
||||
);
|
||||
}
|
||||
|
||||
public static boolean hideSearchTermThumbnail() {
|
||||
return Settings.HIDE_SEARCH_TERM_THUMBNAIL.get();
|
||||
}
|
||||
|
|
@ -726,7 +671,16 @@ public class GeneralPatch {
|
|||
return StringUtils.equalsAny(
|
||||
enumString,
|
||||
"TAB_ACTIVITY", // Notification button
|
||||
"TAB_ACTIVITY_CAIRO" // Notification button (new layout)
|
||||
"TAB_ACTIVITY_CAIRO" // Notification button (New layout)
|
||||
);
|
||||
}
|
||||
|
||||
private static boolean isSearchButton(String enumString) {
|
||||
return StringUtils.equalsAny(
|
||||
enumString,
|
||||
"SEARCH", // Search button
|
||||
"SEARCH_CAIRO", // Search button (New layout)
|
||||
"SEARCH_BOLD" // Search button (Shorts)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,311 @@
|
|||
package app.revanced.extension.youtube.patches.general;
|
||||
|
||||
import static app.revanced.extension.shared.utils.Utils.hideViewUnderCondition;
|
||||
import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.Spanned;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import app.revanced.extension.shared.utils.ResourceUtils;
|
||||
import app.revanced.extension.shared.utils.Utils;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
import app.revanced.extension.youtube.shared.NavigationBar;
|
||||
import app.revanced.extension.youtube.shared.RootView;
|
||||
import app.revanced.extension.youtube.utils.ExtendedUtils;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class NavigationButtonsPatch {
|
||||
|
||||
private static final boolean ENABLE_NARROW_NAVIGATION_BUTTONS
|
||||
= Settings.ENABLE_NARROW_NAVIGATION_BUTTONS.get();
|
||||
|
||||
private static final boolean ENABLE_TRANSLUCENT_NAVIGATION_BAR
|
||||
= Settings.ENABLE_TRANSLUCENT_NAVIGATION_BAR.get();
|
||||
|
||||
private static final boolean HIDE_NAVIGATION_LABEL
|
||||
= Settings.HIDE_NAVIGATION_LABEL.get();
|
||||
|
||||
private static final boolean HIDE_NAVIGATION_BAR
|
||||
= Settings.HIDE_NAVIGATION_BAR.get();
|
||||
|
||||
private static final boolean SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON
|
||||
= Settings.SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON.get();
|
||||
|
||||
private static final boolean REPLACE_NAVIGATION_BUTTON
|
||||
= Settings.REPLACE_NAVIGATION_BUTTON.get();
|
||||
private static final NavigationButton REPLACE_NAVIGATION_BUTTON_TARGET
|
||||
= Settings.REPLACE_NAVIGATION_BUTTON_TARGET.get();
|
||||
private static final List<String> REPLACE_NAVIGATION_BUTTON_TARGET_ENUM_NAMES
|
||||
= REPLACE_NAVIGATION_BUTTON_TARGET.ytEnumNames;
|
||||
|
||||
private static final boolean SET_CAIRO_NOTIFICATION_FILLED_ICON
|
||||
= !REPLACE_NAVIGATION_BUTTON || REPLACE_NAVIGATION_BUTTON_TARGET != NavigationButton.NOTIFICATIONS;
|
||||
|
||||
private static Map<NavigationButton, Boolean> shouldHideMap;
|
||||
|
||||
private static volatile WeakReference<TextView> searchQueryRef = new WeakReference<>(null);
|
||||
|
||||
private static View.OnClickListener openSearchBar;
|
||||
|
||||
private static final View.OnClickListener openSearchBarOnClickListener = v -> {
|
||||
if (RootView.isSearchBarActive() && searchQueryRef.get() != null) {
|
||||
searchQueryRef.get().callOnClick();
|
||||
} else if (openSearchBar != null) {
|
||||
openSearchBar.onClick(v);
|
||||
} else {
|
||||
Context context = v.getContext();
|
||||
Intent intent = new Intent();
|
||||
intent.setAction("com.google.android.youtube.action.open.search");
|
||||
intent.setPackage(context.getPackageName());
|
||||
context.startActivity(intent);
|
||||
}
|
||||
};
|
||||
|
||||
private static int emptyContentCountId = -1;
|
||||
private static int emptyContentDotId = -1;
|
||||
private static int libraryCairoId = -1;
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static Enum<?> search;
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static Enum<?> searchCairo;
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static boolean enableNarrowNavigationButton(boolean original) {
|
||||
return ENABLE_NARROW_NAVIGATION_BUTTONS || original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static boolean enableTranslucentNavigationBar() {
|
||||
return ENABLE_TRANSLUCENT_NAVIGATION_BAR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*
|
||||
* @noinspection ALL
|
||||
*/
|
||||
public static void setCairoNotificationFilledIcon(EnumMap enumMap, Enum tabActivityCairo) {
|
||||
if (SET_CAIRO_NOTIFICATION_FILLED_ICON) {
|
||||
final int fillBellCairoBlack = ResourceUtils.getDrawableIdentifier("yt_fill_bell_cairo_black_24");
|
||||
if (fillBellCairoBlack != 0) {
|
||||
// It's very unlikely, but Google might fix this issue someday.
|
||||
// If so, [fillBellCairoBlack] might already be in enumMap.
|
||||
// That's why 'EnumMap.putIfAbsent()' is used instead of 'EnumMap.put()'.
|
||||
enumMap.putIfAbsent(tabActivityCairo, Integer.valueOf(fillBellCairoBlack));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int getEmptyContentCountId() {
|
||||
if (emptyContentCountId == -1) {
|
||||
emptyContentCountId = ResourceUtils.getIdIdentifier("empty_content_count");
|
||||
}
|
||||
return emptyContentCountId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static View getContentCountId(View view, int original) {
|
||||
if (REPLACE_NAVIGATION_BUTTON && shouldReplace()) {
|
||||
int id = getEmptyContentCountId();
|
||||
if (id != 0) {
|
||||
View emptyView = view.findViewById(id);
|
||||
if (emptyView != null) {
|
||||
return emptyView;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return view.findViewById(original);
|
||||
}
|
||||
|
||||
private static int getEmptyContentDotId() {
|
||||
if (emptyContentDotId == -1) {
|
||||
emptyContentDotId = ResourceUtils.getIdIdentifier("empty_content_dot");
|
||||
}
|
||||
return emptyContentDotId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static View getContentDotId(View view, int original) {
|
||||
if (REPLACE_NAVIGATION_BUTTON && shouldReplace()) {
|
||||
int id = getEmptyContentDotId();
|
||||
if (id != 0) {
|
||||
View emptyView = view.findViewById(id);
|
||||
if (emptyView != null) {
|
||||
return emptyView;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return view.findViewById(original);
|
||||
}
|
||||
|
||||
private static int getLibraryCairoId() {
|
||||
if (libraryCairoId == -1) {
|
||||
libraryCairoId = ResourceUtils.getIdIdentifier("yt_outline_library_cairo_black_24");
|
||||
}
|
||||
return libraryCairoId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static int getLibraryDrawableId(int original) {
|
||||
if (ExtendedUtils.IS_19_26_OR_GREATER &&
|
||||
!ExtendedUtils.isSpoofingToLessThan("19.27.00")) {
|
||||
int libraryCairoId = getLibraryCairoId();
|
||||
if (libraryCairoId != 0) {
|
||||
return libraryCairoId;
|
||||
}
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toolbar buttons (including the YouTube logo) and navigation bar buttons depend on the
|
||||
* '<a href="https://www.youtube.com/youtubei/v1/guide">'/guide' endpoint</a>' requests.
|
||||
* <p>
|
||||
* Therefore, the patch works if the 'osName' value is spoofed only in '/guide' endpoint requests.
|
||||
*
|
||||
* @return osName.
|
||||
*/
|
||||
public static String getOSName() {
|
||||
return SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON
|
||||
? "Android Automotive"
|
||||
// If the setting is off, it should return the original osName (override).
|
||||
// Otherwise, there may be interference with the 'Hide ads' patch.
|
||||
: ExtendedUtils.getOSName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void setSearchBarOnClickListener(View.OnClickListener listener) {
|
||||
if (REPLACE_NAVIGATION_BUTTON) {
|
||||
openSearchBar = listener;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldReplace() {
|
||||
return shouldReplace(NavigationBar.getLastAppNavigationEnum());
|
||||
}
|
||||
|
||||
private static boolean shouldReplace(@Nullable Enum<?> navigationEnum) {
|
||||
return navigationEnum != null && shouldReplace(navigationEnum.name());
|
||||
}
|
||||
|
||||
private static boolean shouldReplace(String lastEnumName) {
|
||||
return lastEnumName != null && REPLACE_NAVIGATION_BUTTON_TARGET_ENUM_NAMES.contains(lastEnumName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
@Nullable
|
||||
public static Enum<?> changeIconType(@Nullable Enum<?> original) {
|
||||
if (REPLACE_NAVIGATION_BUTTON && shouldReplace(original)) {
|
||||
String enumName = original.name();
|
||||
return original.name().endsWith("CAIRO")
|
||||
? searchCairo
|
||||
: search;
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static Spanned changeSpanned(Spanned original) {
|
||||
if (REPLACE_NAVIGATION_BUTTON &&
|
||||
// If the navigation bar label is hidden, there is no need to replace Spanned.
|
||||
!HIDE_NAVIGATION_LABEL &&
|
||||
shouldReplace()
|
||||
) {
|
||||
String lastYTNavigationEnumName = NavigationBar.getLastAppNavigationEnum();
|
||||
return Utils.newSpanUsingStylingOfAnotherSpan(original, ResourceUtils.getString("menu_search"));
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void searchQueryViewLoaded(TextView searchQuery) {
|
||||
if (REPLACE_NAVIGATION_BUTTON) {
|
||||
searchQueryRef = new WeakReference<>(searchQuery);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<NavigationButton, Boolean> getHideMap() {
|
||||
if (shouldHideMap == null || shouldHideMap.isEmpty()) {
|
||||
shouldHideMap = new EnumMap<>(NavigationButton.class) {
|
||||
{
|
||||
put(NavigationButton.HOME, Settings.HIDE_NAVIGATION_HOME_BUTTON.get());
|
||||
put(NavigationButton.SHORTS, Settings.HIDE_NAVIGATION_SHORTS_BUTTON.get());
|
||||
put(NavigationButton.SUBSCRIPTIONS, Settings.HIDE_NAVIGATION_SUBSCRIPTIONS_BUTTON.get());
|
||||
put(NavigationButton.CREATE, Settings.HIDE_NAVIGATION_CREATE_BUTTON.get());
|
||||
put(NavigationButton.NOTIFICATIONS, Settings.HIDE_NAVIGATION_NOTIFICATIONS_BUTTON.get());
|
||||
put(NavigationButton.LIBRARY, Settings.HIDE_NAVIGATION_LIBRARY_BUTTON.get());
|
||||
}
|
||||
};
|
||||
}
|
||||
return shouldHideMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void navigationTabCreated(NavigationButton button, View tabView) {
|
||||
if (REPLACE_NAVIGATION_BUTTON && button == REPLACE_NAVIGATION_BUTTON_TARGET) {
|
||||
tabView.setOnClickListener(openSearchBarOnClickListener);
|
||||
Utils.runOnMainThread(() -> tabView.setOnClickListener(openSearchBarOnClickListener));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (BooleanUtils.isTrue(getHideMap().get(button))) {
|
||||
tabView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void hideNavigationLabel(TextView view) {
|
||||
hideViewUnderCondition(HIDE_NAVIGATION_LABEL, view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void hideNavigationBar(View view) {
|
||||
hideViewUnderCondition(HIDE_NAVIGATION_BAR, view);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -49,6 +49,7 @@ import app.revanced.extension.youtube.patches.swipe.SwipeControlsPatch.SwipeOver
|
|||
import app.revanced.extension.youtube.patches.swipe.SwipeControlsPatch.SwipeOverlaySeekColorAvailability;
|
||||
import app.revanced.extension.youtube.patches.utils.PatchStatus;
|
||||
import app.revanced.extension.youtube.patches.video.CustomPlaybackSpeedPatch.PlaybackSpeedMenuType;
|
||||
import app.revanced.extension.youtube.shared.NavigationBar.NavigationButton;
|
||||
import app.revanced.extension.youtube.shared.PlaylistIdPrefix;
|
||||
import app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController.SponsorBlockDuration;
|
||||
import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings;
|
||||
|
|
@ -202,6 +203,8 @@ public class Settings extends BaseSettings {
|
|||
"revanced_switch_create_with_notifications_button_user_dialog_message");
|
||||
public static final BooleanSetting ENABLE_TRANSLUCENT_NAVIGATION_BAR = new BooleanSetting("revanced_enable_translucent_navigation_bar", FALSE, true);
|
||||
public static final BooleanSetting HIDE_NAVIGATION_BAR = new BooleanSetting("revanced_hide_navigation_bar", FALSE, true);
|
||||
public static final BooleanSetting REPLACE_NAVIGATION_BUTTON = new BooleanSetting("revanced_replace_navigation_button", FALSE, true);
|
||||
public static final EnumSetting<NavigationButton> REPLACE_NAVIGATION_BUTTON_TARGET = new EnumSetting<>("revanced_replace_navigation_button_target", NavigationButton.SHORTS, true, parent(REPLACE_NAVIGATION_BUTTON));
|
||||
|
||||
// PreferenceScreen: General - Override buttons
|
||||
public static final BooleanSetting OVERRIDE_PLAYLIST_DOWNLOAD_BUTTON = new BooleanSetting("revanced_override_playlist_download_button", FALSE, true);
|
||||
|
|
@ -261,6 +264,7 @@ public class Settings extends BaseSettings {
|
|||
public static final BooleanSetting HIDE_TOOLBAR_CAST_BUTTON = new BooleanSetting("revanced_hide_toolbar_cast_button", TRUE, true);
|
||||
public static final BooleanSetting HIDE_TOOLBAR_CREATE_BUTTON = new BooleanSetting("revanced_hide_toolbar_create_button", FALSE, true);
|
||||
public static final BooleanSetting HIDE_TOOLBAR_NOTIFICATION_BUTTON = new BooleanSetting("revanced_hide_toolbar_notification_button", FALSE, true);
|
||||
public static final BooleanSetting HIDE_TOOLBAR_SEARCH_BUTTON = new BooleanSetting("revanced_hide_toolbar_search_button", FALSE, true);
|
||||
public static final BooleanSetting HIDE_SEARCH_TERM_THUMBNAIL = new BooleanSetting("revanced_hide_search_term_thumbnail", FALSE);
|
||||
public static final BooleanSetting HIDE_IMAGE_SEARCH_BUTTON = new BooleanSetting("revanced_hide_image_search_button", FALSE, true);
|
||||
public static final BooleanSetting HIDE_VOICE_SEARCH_BUTTON = new BooleanSetting("revanced_hide_voice_search_button", FALSE, true);
|
||||
|
|
|
|||
|
|
@ -45,11 +45,12 @@ public class SpoofAppVersionPreference extends CustomDialogListPreference {
|
|||
* Enum representing supported YouTube Music app with their display names, package names.
|
||||
*/
|
||||
private enum AppVersion {
|
||||
YT_20_05_46("20.05.46"),
|
||||
YT_19_33_37("19.33.37"),
|
||||
YT_19_28_42("19.28.42"),
|
||||
YT_19_26_42("19.26.42"),
|
||||
YT_19_01_34("19.01.34"),
|
||||
YT_20_13_41(),
|
||||
YT_20_05_46(),
|
||||
YT_19_33_37(),
|
||||
YT_19_28_42(),
|
||||
YT_19_26_42(),
|
||||
YT_19_01_34(),
|
||||
OTHER(sf("revanced_spoof_app_version_other_item").toString());
|
||||
|
||||
@NonNull
|
||||
|
|
@ -65,12 +66,15 @@ public class SpoofAppVersionPreference extends CustomDialogListPreference {
|
|||
public final String entryName;
|
||||
public final String versionName;
|
||||
|
||||
AppVersion(String versionName) {
|
||||
this.entryName = name().startsWith("YT")
|
||||
? sf("revanced_spoof_app_version_target_entry" +
|
||||
name().replaceAll("YT", "")).toString()
|
||||
: versionName;
|
||||
this.versionName = versionName;
|
||||
AppVersion() {
|
||||
String tmpVersionName = name().replaceAll("YT_", "");
|
||||
this.entryName = sf("revanced_spoof_app_version_target_entry_" + tmpVersionName).toString();
|
||||
this.versionName = tmpVersionName.replaceAll("_", ".");
|
||||
}
|
||||
|
||||
AppVersion(String itemName) {
|
||||
this.entryName = itemName;
|
||||
this.versionName = itemName;
|
||||
}
|
||||
|
||||
public boolean isAvailable() {
|
||||
|
|
|
|||
|
|
@ -117,6 +117,10 @@ public final class NavigationBar {
|
|||
@Nullable
|
||||
private static String lastYTNavigationEnumName;
|
||||
|
||||
public static String getLastAppNavigationEnum() {
|
||||
return lastYTNavigationEnumName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
|
|
@ -223,10 +227,6 @@ public final class NavigationBar {
|
|||
* This tab will never be in a selected state, even if the create video UI is on screen.
|
||||
*/
|
||||
CREATE("CREATION_TAB_LARGE", "CREATION_TAB_LARGE_CAIRO"),
|
||||
/**
|
||||
* Only shown to automotive layout.
|
||||
*/
|
||||
EXPLORE("TAB_EXPLORE"),
|
||||
SUBSCRIPTIONS("PIVOT_SUBSCRIPTIONS", "TAB_SUBSCRIPTIONS_CAIRO"),
|
||||
/**
|
||||
* Notifications tab. Only present when
|
||||
|
|
@ -281,7 +281,7 @@ public final class NavigationBar {
|
|||
/**
|
||||
* YouTube enum name for this tab.
|
||||
*/
|
||||
private final List<String> ytEnumNames;
|
||||
public final List<String> ytEnumNames;
|
||||
|
||||
NavigationButton(String... ytEnumNames) {
|
||||
this.ytEnumNames = Arrays.asList(ytEnumNames);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,29 @@ public class ExtendedUtils extends PackageUtils {
|
|||
public static final boolean IS_19_29_OR_GREATER = isVersionOrGreater("19.29.00");
|
||||
public static final boolean IS_19_34_OR_GREATER = isVersionOrGreater("19.34.00");
|
||||
public static final boolean IS_20_09_OR_GREATER = isVersionOrGreater("20.09.00");
|
||||
public static final boolean IS_20_10_OR_GREATER = isVersionOrGreater("20.10.00");
|
||||
|
||||
public static final boolean IS_ARC = hasSystemFeature("org.chromium.arc");
|
||||
public static final boolean IS_AUTOMOTIVE = hasSystemFeature("android.hardware.type.automotive");
|
||||
public static final boolean IS_WATCH = hasSystemFeature("android.hardware.type.watch");
|
||||
|
||||
private static String osName = "";
|
||||
|
||||
public static String getOSName() {
|
||||
if (osName.isEmpty()) {
|
||||
if (IS_WATCH) {
|
||||
osName = "Android Wear";
|
||||
} else if (IS_AUTOMOTIVE) {
|
||||
osName = "Android Automotive";
|
||||
} else if (IS_ARC) {
|
||||
osName = "ChromeOS";
|
||||
} else {
|
||||
osName = "Android";
|
||||
}
|
||||
}
|
||||
|
||||
return osName;
|
||||
}
|
||||
|
||||
public static boolean isFullscreenHidden() {
|
||||
return Settings.DISABLE_ENGAGEMENT_PANEL.get() || Settings.HIDE_QUICK_ACTIONS.get();
|
||||
|
|
|
|||
|
|
@ -707,6 +707,10 @@ public final class app/revanced/patches/shared/spoof/appversion/BaseSpoofAppVers
|
|||
public static final fun baseSpoofAppVersionPatch (Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/shared/spoof/guide/SpoofClientGuideEndpointPatchKt {
|
||||
public static final fun getSpoofClientGuideEndpointPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/shared/spoof/streamingdata/FingerprintsKt {
|
||||
public static final field STREAMING_DATA_OUTER_CLASS Ljava/lang/String;
|
||||
}
|
||||
|
|
@ -1183,6 +1187,7 @@ public final class app/revanced/patches/youtube/utils/navigation/NavigationBarHo
|
|||
public static final fun addBottomBarContainerHook (Ljava/lang/String;)V
|
||||
public static final fun getHookNavigationButtonCreated ()Lkotlin/jvm/functions/Function1;
|
||||
public static final fun getNavigationBarHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
public static final fun getNavigationButtonsMethod ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
||||
public static final fun setHookNavigationButtonCreated (Lkotlin/jvm/functions/Function1;)V
|
||||
}
|
||||
|
||||
|
|
@ -1231,6 +1236,7 @@ public final class app/revanced/patches/youtube/utils/playservice/VersionCheckPa
|
|||
public static final fun is_19_32_or_greater ()Z
|
||||
public static final fun is_19_34_or_greater ()Z
|
||||
public static final fun is_19_36_or_greater ()Z
|
||||
public static final fun is_19_37_or_greater ()Z
|
||||
public static final fun is_19_41_or_greater ()Z
|
||||
public static final fun is_19_42_or_greater ()Z
|
||||
public static final fun is_19_43_or_greater ()Z
|
||||
|
|
@ -1242,6 +1248,7 @@ public final class app/revanced/patches/youtube/utils/playservice/VersionCheckPa
|
|||
public static final fun is_20_03_or_greater ()Z
|
||||
public static final fun is_20_04_or_greater ()Z
|
||||
public static final fun is_20_05_or_greater ()Z
|
||||
public static final fun is_20_06_or_greater ()Z
|
||||
public static final fun is_20_07_or_greater ()Z
|
||||
public static final fun is_20_09_or_greater ()Z
|
||||
public static final fun is_20_10_or_greater ()Z
|
||||
|
|
@ -1272,6 +1279,7 @@ public final class app/revanced/patches/youtube/utils/resourceid/SharedResourceI
|
|||
public static final fun getAccountSwitcherAccessibility ()J
|
||||
public static final fun getActionBarRingo ()J
|
||||
public static final fun getActionBarRingoBackground ()J
|
||||
public static final fun getActionBarSearchResultsViewMic ()J
|
||||
public static final fun getAdAttribution ()J
|
||||
public static final fun getAppRelatedEndScreenResults ()J
|
||||
public static final fun getAppearance ()J
|
||||
|
|
@ -1326,6 +1334,7 @@ public final class app/revanced/patches/youtube/utils/resourceid/SharedResourceI
|
|||
public static final fun getLikeTapFeedbackCairo ()J
|
||||
public static final fun getMdxSeamlessTVSignInDrawerFragmentTitle ()J
|
||||
public static final fun getMenuItemView ()J
|
||||
public static final fun getMenuSearch ()J
|
||||
public static final fun getMiniplayerMaxSize ()J
|
||||
public static final fun getModernMiniPlayerClose ()J
|
||||
public static final fun getModernMiniPlayerExpand ()J
|
||||
|
|
@ -1333,6 +1342,8 @@ public final class app/revanced/patches/youtube/utils/resourceid/SharedResourceI
|
|||
public static final fun getModernMiniPlayerOverlayActionButton ()J
|
||||
public static final fun getModernMiniPlayerRewindButton ()J
|
||||
public static final fun getMusicAppDeeplinkButtonView ()J
|
||||
public static final fun getNewContentCount ()J
|
||||
public static final fun getNewContentDot ()J
|
||||
public static final fun getNotificationBigPictureIconWidth ()J
|
||||
public static final fun getOfflineActionsVideoDeletedUndoSnackbarText ()J
|
||||
public static final fun getOfflineNoContentBodyTextNotOfflineEligible ()J
|
||||
|
|
@ -1360,6 +1371,8 @@ public final class app/revanced/patches/youtube/utils/resourceid/SharedResourceI
|
|||
public static final fun getRelatedChipCloudMargin ()J
|
||||
public static final fun getRightComment ()J
|
||||
public static final fun getScrimOverlay ()J
|
||||
public static final fun getSearchBox ()J
|
||||
public static final fun getSearchQuery ()J
|
||||
public static final fun getSeeMoreProceedingHeader ()J
|
||||
public static final fun getSeekEasyHorizontalTouchOffsetToStartScrubbing ()J
|
||||
public static final fun getSeekUndoEduOverlayStub ()J
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ group = "app.revanced"
|
|||
|
||||
patches {
|
||||
about {
|
||||
name = "ReVanced Patches"
|
||||
description = "Patches for ReVanced"
|
||||
source = "git@github.com:revanced/revanced-patches.git"
|
||||
author = "ReVanced"
|
||||
contact = "contact@revanced.app"
|
||||
website = "https://revanced.app"
|
||||
name = "RVX Patches"
|
||||
description = "Patches for RVX"
|
||||
source = "git@github.com:anddea/revanced-patches.git"
|
||||
author = "Aaron Veil (anddea)"
|
||||
contact = "https://github.com/anddea/revanced-patches/issues"
|
||||
website = "https://rvxtranslate.netlify.app/"
|
||||
license = "GNU General Public License v3.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,24 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
|||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
|
||||
internal const val ANDROID_AUTOMOTIVE_STRING = "Android Automotive"
|
||||
internal const val CLIENT_INFO_CLASS_DESCRIPTOR =
|
||||
"Lcom/google/protos/youtube/api/innertube/InnertubeContext\$ClientInfo;"
|
||||
|
||||
internal val autoMotiveFingerprint = legacyFingerprint(
|
||||
name = "autoMotiveFingerprint",
|
||||
opcodes = listOf(
|
||||
Opcode.GOTO,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ
|
||||
),
|
||||
strings = listOf(ANDROID_AUTOMOTIVE_STRING),
|
||||
customFingerprint = { _, classDef ->
|
||||
!classDef.type.startsWith("Lapp/")
|
||||
}
|
||||
)
|
||||
|
||||
internal val clientTypeFingerprint = legacyFingerprint(
|
||||
name = "clientTypeFingerprint",
|
||||
opcodes = listOf(
|
||||
|
|
@ -130,7 +145,7 @@ internal val formatStreamModelToStringFingerprint = legacyFingerprint(
|
|||
AUDIO_TRACK_DISPLAY_NAME_STRING,
|
||||
AUDIO_TRACK_ID_STRING
|
||||
),
|
||||
customFingerprint = { method, classDef ->
|
||||
customFingerprint = { method, _ ->
|
||||
method.name == "toString"
|
||||
}
|
||||
)
|
||||
|
|
@ -236,7 +251,7 @@ internal val playbackStartParametersToStringFingerprint = legacyFingerprint(
|
|||
FIXED_RESOLUTION_STRING,
|
||||
WATCH_NEXT_RESPONSE_PROCESSING_DELAY_STRING
|
||||
),
|
||||
customFingerprint = { method, classDef ->
|
||||
customFingerprint = { method, _ ->
|
||||
method.name == "toString"
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
package app.revanced.patches.shared.spoof.guide
|
||||
|
||||
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
|
||||
|
||||
internal val authenticationChangeListenerFingerprint = legacyFingerprint(
|
||||
name = "authenticationChangeListenerFingerprint",
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||
strings = listOf("Authentication changed while request was being made"),
|
||||
customFingerprint = { method, _ ->
|
||||
indexOfMessageLiteBuilderReference(method) >= 0
|
||||
}
|
||||
)
|
||||
|
||||
internal fun indexOfMessageLiteBuilderReference(method: Method, type: String = "L") =
|
||||
method.indexOfFirstInstruction {
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
reference?.parameterTypes?.isEmpty() == true &&
|
||||
reference.returnType.startsWith(type)
|
||||
}
|
||||
|
||||
internal val guideEndpointConstructorFingerprint = legacyFingerprint(
|
||||
name = "guideEndpointConstructorFingerprint",
|
||||
returnType = "V",
|
||||
strings = listOf("guide"),
|
||||
customFingerprint = { method, _ ->
|
||||
method.name == "<init>"
|
||||
}
|
||||
)
|
||||
|
||||
internal val guideEndpointRequestBodyFingerprint = legacyFingerprint(
|
||||
name = "guideEndpointRequestBodyFingerprint",
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
||||
parameters = emptyList(),
|
||||
opcodes = listOf(Opcode.RETURN_VOID),
|
||||
)
|
||||
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
package app.revanced.patches.shared.spoof.guide
|
||||
|
||||
import app.revanced.patcher.Match
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patches.shared.ANDROID_AUTOMOTIVE_STRING
|
||||
import app.revanced.patches.shared.CLIENT_INFO_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.shared.autoMotiveFingerprint
|
||||
import app.revanced.patches.shared.clientTypeFingerprint
|
||||
import app.revanced.patches.shared.createPlayerRequestBodyWithModelFingerprint
|
||||
import app.revanced.patches.shared.indexOfClientInfoInstruction
|
||||
import app.revanced.util.fingerprint.matchOrThrow
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstStringInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
|
||||
private lateinit var insertMatch: Match
|
||||
private lateinit var clientInfoField: FieldReference
|
||||
private lateinit var messageLiteBuilderField: FieldReference
|
||||
private lateinit var messageLiteBuilderMethod: MethodReference
|
||||
|
||||
val spoofClientGuideEndpointPatch = bytecodePatch(
|
||||
description = "spoofClientGuideEndpointPatch"
|
||||
) {
|
||||
execute {
|
||||
clientTypeFingerprint.methodOrThrow().apply {
|
||||
val clientInfoIndex = indexOfClientInfoInstruction(this)
|
||||
val messageLiteBuilderIndex =
|
||||
indexOfFirstInstructionReversedOrThrow(clientInfoIndex) {
|
||||
opcode == Opcode.IGET_OBJECT &&
|
||||
getReference<FieldReference>()?.name == "instance"
|
||||
}
|
||||
|
||||
clientInfoField =
|
||||
getInstruction<ReferenceInstruction>(clientInfoIndex).reference as FieldReference
|
||||
messageLiteBuilderField =
|
||||
getInstruction<ReferenceInstruction>(messageLiteBuilderIndex).reference as FieldReference
|
||||
}
|
||||
|
||||
authenticationChangeListenerFingerprint.methodOrThrow().apply {
|
||||
val messageLiteBuilderIndex =
|
||||
indexOfMessageLiteBuilderReference(this, messageLiteBuilderField.definingClass)
|
||||
|
||||
messageLiteBuilderMethod =
|
||||
getInstruction<ReferenceInstruction>(messageLiteBuilderIndex).reference as MethodReference
|
||||
}
|
||||
|
||||
insertMatch = guideEndpointRequestBodyFingerprint
|
||||
.matchOrThrow(guideEndpointConstructorFingerprint)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun addClientInfoHook(
|
||||
helperMethodName: String,
|
||||
smaliInstructions: String,
|
||||
insertLast: Boolean = false,
|
||||
) = insertMatch.let {
|
||||
it.method.apply {
|
||||
it.classDef.methods.add(
|
||||
ImmutableMethod(
|
||||
definingClass,
|
||||
helperMethodName,
|
||||
emptyList(),
|
||||
"V",
|
||||
AccessFlags.PRIVATE.value or AccessFlags.FINAL.value,
|
||||
annotations,
|
||||
null,
|
||||
MutableMethodImplementation(5),
|
||||
).toMutable().apply {
|
||||
addInstructionsWithLabels(
|
||||
0, """
|
||||
invoke-virtual {p0}, $messageLiteBuilderMethod
|
||||
move-result-object v0
|
||||
iget-object v0, v0, $messageLiteBuilderField
|
||||
check-cast v0, ${clientInfoField.definingClass}
|
||||
iget-object v1, v0, $clientInfoField
|
||||
if-eqz v1, :ignore
|
||||
""" + smaliInstructions + """
|
||||
:ignore
|
||||
return-void
|
||||
""",
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
addInstruction(
|
||||
if (insertLast) implementation!!.instructions.lastIndex else 0,
|
||||
"invoke-direct/range { p0 .. p0 }, $definingClass->$helperMethodName()V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
context(BytecodePatchContext)
|
||||
internal fun addClientOSVersionHook(
|
||||
helperMethodName: String,
|
||||
descriptor: String,
|
||||
isObject: Boolean = false,
|
||||
insertLast: Boolean = true,
|
||||
) {
|
||||
val osNameLocalField = with (autoMotiveFingerprint.methodOrThrow()) {
|
||||
val stringIndex = indexOfFirstStringInstructionOrThrow(ANDROID_AUTOMOTIVE_STRING)
|
||||
val fieldType = if (isObject) "Ljava/lang/Object;" else "Ljava/lang/String;"
|
||||
val osNameFieldIndex = indexOfFirstInstructionOrThrow(stringIndex) {
|
||||
val reference = getReference<FieldReference>()
|
||||
opcode == Opcode.IPUT_OBJECT &&
|
||||
reference?.type == fieldType &&
|
||||
reference.definingClass == definingClass
|
||||
}
|
||||
|
||||
getInstruction<ReferenceInstruction>(osNameFieldIndex).reference as FieldReference
|
||||
}
|
||||
|
||||
createPlayerRequestBodyWithModelFingerprint.methodOrThrow().apply {
|
||||
val osNameLocalFieldIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.IGET_OBJECT &&
|
||||
getReference<FieldReference>() == osNameLocalField
|
||||
}
|
||||
val osNameIndex =
|
||||
indexOfFirstInstructionOrThrow(osNameLocalFieldIndex - 1) {
|
||||
val reference = getReference<FieldReference>()
|
||||
opcode == Opcode.IPUT_OBJECT &&
|
||||
reference?.type == "Ljava/lang/String;" &&
|
||||
reference.definingClass == CLIENT_INFO_CLASS_DESCRIPTOR
|
||||
}
|
||||
val osNameReference =
|
||||
getInstruction<ReferenceInstruction>(osNameIndex).reference
|
||||
|
||||
addClientInfoHook(
|
||||
helperMethodName,
|
||||
"""
|
||||
invoke-static {}, $descriptor
|
||||
move-result-object v2
|
||||
iput-object v2, v1, $osNameReference
|
||||
""",
|
||||
insertLast
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,17 +1,24 @@
|
|||
package app.revanced.patches.youtube.ads.general
|
||||
|
||||
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.replaceInstruction
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.ANDROID_AUTOMOTIVE_STRING
|
||||
import app.revanced.patches.shared.ads.adsPatch
|
||||
import app.revanced.patches.shared.autoMotiveFingerprint
|
||||
import app.revanced.patches.shared.litho.addLithoFilter
|
||||
import app.revanced.patches.shared.litho.lithoFilterPatch
|
||||
import app.revanced.patches.shared.spoof.guide.addClientOSVersionHook
|
||||
import app.revanced.patches.shared.spoof.guide.spoofClientGuideEndpointPatch
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.ADS_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH
|
||||
import app.revanced.patches.youtube.utils.fix.litho.lithoLayoutPatch
|
||||
import app.revanced.patches.youtube.utils.patch.PatchList.HIDE_ADS
|
||||
import app.revanced.patches.youtube.utils.playservice.is_20_06_or_greater
|
||||
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.adAttribution
|
||||
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
||||
|
|
@ -19,9 +26,11 @@ import app.revanced.patches.youtube.utils.settings.settingsPatch
|
|||
import app.revanced.util.findMutableMethodOf
|
||||
import app.revanced.util.fingerprint.matchOrThrow
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.indexOfFirstStringInstructionOrThrow
|
||||
import app.revanced.util.injectHideViewCall
|
||||
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
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
|
||||
|
|
@ -39,6 +48,8 @@ val adsPatch = adsPatch(
|
|||
lithoFilterPatch,
|
||||
lithoLayoutPatch,
|
||||
sharedResourceIdPatch,
|
||||
spoofClientGuideEndpointPatch,
|
||||
versionCheckPatch,
|
||||
)
|
||||
},
|
||||
classDescriptor = ADS_CLASS_DESCRIPTOR,
|
||||
|
|
@ -128,6 +139,31 @@ val adsPatch = adsPatch(
|
|||
|
||||
// endregion
|
||||
|
||||
// region patch for hide shorts ad
|
||||
|
||||
// Hide Shorts ads by changing 'OSName' to 'Android Automotive'
|
||||
autoMotiveFingerprint.methodOrThrow().apply {
|
||||
val insertIndex = indexOfFirstStringInstructionOrThrow(ANDROID_AUTOMOTIVE_STRING) - 1
|
||||
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {v$insertRegister}, $ADS_CLASS_DESCRIPTOR->hideShortsAds(Z)Z
|
||||
move-result v$insertRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
// If 'OSName' is changed to 'Android Automotive' in all requests, a Notification button will appear in the navigation bar
|
||||
// To fix this side effect, requests to the '/guide' endpoint, which are related to navigation buttons, use the original 'OSName'
|
||||
addClientOSVersionHook(
|
||||
"patch_setClientOSNameByAdsPatch",
|
||||
"$ADS_CLASS_DESCRIPTOR->overrideOSName()Ljava/lang/String;",
|
||||
is_20_06_or_greater
|
||||
)
|
||||
|
||||
// endregion
|
||||
|
||||
// region add settings
|
||||
|
||||
addPreference(
|
||||
|
|
|
|||
|
|
@ -20,12 +20,14 @@ import app.revanced.patches.youtube.utils.patch.PatchList.HIDE_FEED_COMPONENTS
|
|||
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
|
||||
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.is_20_10_or_greater
|
||||
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.bar
|
||||
import app.revanced.patches.youtube.utils.resourceid.captionToggleContainer
|
||||
import app.revanced.patches.youtube.utils.resourceid.channelListSubMenu
|
||||
import app.revanced.patches.youtube.utils.resourceid.contentPill
|
||||
import app.revanced.patches.youtube.utils.resourceid.horizontalCardList
|
||||
import app.revanced.patches.youtube.utils.resourceid.relatedChipCloudMargin
|
||||
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.utils.scrollTopParentFingerprint
|
||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
||||
|
|
@ -208,11 +210,6 @@ val feedComponentsPatch = bytecodePatch(
|
|||
"""
|
||||
}
|
||||
|
||||
relatedChipCloudFingerprint.patch<OneRegisterInstruction>(1) { register ->
|
||||
"invoke-static { v$register }, " +
|
||||
"$FEED_CLASS_DESCRIPTOR->hideCategoryBarInRelatedVideos(Landroid/view/View;)V"
|
||||
}
|
||||
|
||||
searchResultsChipBarFingerprint.patch<OneRegisterInstruction>(-1, -2) { register ->
|
||||
"""
|
||||
invoke-static { v$register }, $FEED_CLASS_DESCRIPTOR->hideCategoryBarInSearch(I)I
|
||||
|
|
@ -220,6 +217,51 @@ val feedComponentsPatch = bytecodePatch(
|
|||
"""
|
||||
}
|
||||
|
||||
relatedChipCloudFingerprint.methodOrThrow().apply {
|
||||
val literalIndex =
|
||||
indexOfFirstLiteralInstructionOrThrow(relatedChipCloudMargin)
|
||||
val viewIndex =
|
||||
indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT_OBJECT)
|
||||
val viewRegister =
|
||||
getInstruction<OneRegisterInstruction>(viewIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
viewIndex + 1,
|
||||
"invoke-static { v$viewRegister }, " +
|
||||
"$FEED_CLASS_DESCRIPTOR->hideCategoryBarInRelatedVideos(Landroid/view/View;)V"
|
||||
)
|
||||
|
||||
if (is_20_10_or_greater) {
|
||||
val heightIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "setMinimumHeight"
|
||||
}
|
||||
val heightRegister =
|
||||
getInstruction<FiveRegisterInstruction>(heightIndex).registerD
|
||||
|
||||
addInstructions(
|
||||
heightIndex, """
|
||||
invoke-static { v$heightRegister }, $FEED_CLASS_DESCRIPTOR->hideCategoryBarInRelatedVideos(I)I
|
||||
move-result v$heightRegister
|
||||
"""
|
||||
)
|
||||
|
||||
val experimentalFlagIndex =
|
||||
indexOfFirstLiteralInstructionOrThrow(45682279L)
|
||||
val booleanIndex =
|
||||
indexOfFirstInstructionOrThrow(experimentalFlagIndex, Opcode.MOVE_RESULT)
|
||||
val booleanRegister =
|
||||
getInstruction<OneRegisterInstruction>(booleanIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
booleanIndex + 1, """
|
||||
invoke-static { v$booleanRegister }, $FEED_CLASS_DESCRIPTOR->hideCategoryBarInRelatedVideos(Z)Z
|
||||
move-result v$booleanRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region patch for hide mix playlists
|
||||
|
|
|
|||
|
|
@ -129,11 +129,6 @@ internal val relatedChipCloudFingerprint = legacyFingerprint(
|
|||
name = "relatedChipCloudFingerprint",
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
opcodes = listOf(
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
),
|
||||
literals = listOf(relatedChipCloudMargin),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ package app.revanced.patches.youtube.general.formfactor
|
|||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.shared.CLIENT_INFO_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.shared.createPlayerRequestBodyWithModelFingerprint
|
||||
import app.revanced.patches.shared.spoof.guide.addClientInfoHook
|
||||
import app.revanced.patches.shared.spoof.guide.spoofClientGuideEndpointPatch
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_PATH
|
||||
import app.revanced.patches.youtube.utils.navigation.hookNavigationButtonCreated
|
||||
import app.revanced.patches.youtube.utils.navigation.navigationBarHookPatch
|
||||
import app.revanced.patches.youtube.utils.patch.PatchList.CHANGE_FORM_FACTOR
|
||||
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
|
||||
|
|
@ -19,6 +21,7 @@ import app.revanced.util.getReference
|
|||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
|
|
@ -36,6 +39,7 @@ val changeFormFactorPatch = bytecodePatch(
|
|||
settingsPatch,
|
||||
playerTypeHookPatch,
|
||||
navigationBarHookPatch,
|
||||
spoofClientGuideEndpointPatch,
|
||||
)
|
||||
|
||||
execute {
|
||||
|
|
@ -44,18 +48,41 @@ val changeFormFactorPatch = bytecodePatch(
|
|||
.definingClassOrThrow()
|
||||
|
||||
createPlayerRequestBodyWithModelFingerprint.methodOrThrow().apply {
|
||||
val index = indexOfFirstInstructionOrThrow {
|
||||
val ordinalIndex = indexOfFirstInstructionOrThrow {
|
||||
val reference = getReference<FieldReference>()
|
||||
opcode == Opcode.IGET &&
|
||||
reference?.definingClass == formFactorEnumClass &&
|
||||
reference.type == "I"
|
||||
}
|
||||
val register = getInstruction<TwoRegisterInstruction>(index).registerA
|
||||
val ordinalRegister = getInstruction<TwoRegisterInstruction>(ordinalIndex).registerA
|
||||
|
||||
// This patch changes the 'clientFormFactor' value to a different value
|
||||
addInstructions(
|
||||
index + 1, """
|
||||
invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->getFormFactor(I)I
|
||||
move-result v$register
|
||||
ordinalIndex + 1, """
|
||||
invoke-static {v$ordinalRegister}, $EXTENSION_CLASS_DESCRIPTOR->getFormFactor(I)I
|
||||
move-result v$ordinalRegister
|
||||
"""
|
||||
)
|
||||
|
||||
val clientFormFactorOrdinalIndex =
|
||||
indexOfFirstInstructionOrThrow(ordinalIndex - 1) {
|
||||
val reference = getReference<FieldReference>()
|
||||
opcode == Opcode.IPUT &&
|
||||
reference?.type == "I" &&
|
||||
reference.definingClass == CLIENT_INFO_CLASS_DESCRIPTOR
|
||||
}
|
||||
val clientFormFactorOrdinalReference =
|
||||
getInstruction<ReferenceInstruction>(clientFormFactorOrdinalIndex).reference
|
||||
|
||||
// Changing 'clientFormFactor' in all requests will also affect the navigation bar
|
||||
// If 'clientFormFactor' is 'AUTOMOTIVE_FORM_FACTOR', the 'Shorts' button in the navigation bar will change to 'Explore'
|
||||
// To fix this side effect, requests to the '/guide' endpoint, which are related to navigation buttons, use the original 'clientFormFactor'
|
||||
addClientInfoHook(
|
||||
"patch_setClientFormFactor",
|
||||
"""
|
||||
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->getFormFactor()I
|
||||
move-result v2
|
||||
iput v2, v1, $clientFormFactorOrdinalReference
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
|
@ -74,8 +101,6 @@ val changeFormFactorPatch = bytecodePatch(
|
|||
}
|
||||
}
|
||||
|
||||
hookNavigationButtonCreated(EXTENSION_CLASS_DESCRIPTOR)
|
||||
|
||||
// region add settings
|
||||
|
||||
addPreference(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
package app.revanced.patches.youtube.general.navigation
|
||||
|
||||
import app.revanced.patches.youtube.utils.YOUTUBE_PIVOT_BAR_CLASS_TYPE
|
||||
import app.revanced.patches.youtube.utils.resourceid.actionBarSearchResultsViewMic
|
||||
import app.revanced.patches.youtube.utils.resourceid.newContentCount
|
||||
import app.revanced.patches.youtube.utils.resourceid.newContentDot
|
||||
import app.revanced.patches.youtube.utils.resourceid.searchBox
|
||||
import app.revanced.patches.youtube.utils.resourceid.searchQuery
|
||||
import app.revanced.patches.youtube.utils.resourceid.youTubeLogo
|
||||
import app.revanced.patches.youtube.utils.resourceid.ytFillBell
|
||||
import app.revanced.patches.youtube.utils.resourceid.ytOutlineLibrary
|
||||
import app.revanced.util.fingerprint.legacyFingerprint
|
||||
|
|
@ -8,24 +14,37 @@ import app.revanced.util.or
|
|||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal const val ANDROID_AUTOMOTIVE_STRING = "Android Automotive"
|
||||
internal const val UNKNOWN_STRING = "UNKNOWN"
|
||||
internal const val SEARCH_STRING = "SEARCH"
|
||||
internal const val SEARCH_CAIRO_STRING = "SEARCH_CAIRO"
|
||||
internal const val TAB_ACTIVITY_STRING = "TAB_ACTIVITY"
|
||||
internal const val TAB_ACTIVITY_CAIRO_STRING = "TAB_ACTIVITY_CAIRO"
|
||||
|
||||
internal val autoMotiveFingerprint = legacyFingerprint(
|
||||
name = "autoMotiveFingerprint",
|
||||
opcodes = listOf(
|
||||
Opcode.GOTO,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ
|
||||
),
|
||||
strings = listOf(ANDROID_AUTOMOTIVE_STRING)
|
||||
internal val actionBarSearchResultsFingerprint = legacyFingerprint(
|
||||
name = "actionBarSearchResultsFingerprint",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Landroid/view/View;",
|
||||
literals = listOf(actionBarSearchResultsViewMic, searchQuery),
|
||||
)
|
||||
|
||||
internal val imageEnumConstructorFingerprint = legacyFingerprint(
|
||||
name = "imageEnumConstructorFingerprint",
|
||||
returnType = "V",
|
||||
strings = listOf(TAB_ACTIVITY_CAIRO_STRING)
|
||||
strings = listOf(
|
||||
UNKNOWN_STRING,
|
||||
SEARCH_STRING,
|
||||
TAB_ACTIVITY_STRING
|
||||
)
|
||||
)
|
||||
|
||||
internal val pivotBarBuilderFingerprint = legacyFingerprint(
|
||||
name = "pivotBarBuilderFingerprint",
|
||||
returnType = "V",
|
||||
literals = listOf(newContentCount, newContentDot),
|
||||
customFingerprint = { method, classDef ->
|
||||
method.name == "<init>" &&
|
||||
classDef.fields.find { it.type.endsWith("/PivotBar;") } != null
|
||||
}
|
||||
)
|
||||
|
||||
internal val pivotBarChangedFingerprint = legacyFingerprint(
|
||||
|
|
@ -71,6 +90,24 @@ internal val pivotBarStyleFingerprint = legacyFingerprint(
|
|||
}
|
||||
)
|
||||
|
||||
// 19.37 ~
|
||||
internal val searchBarOnClickListenerFingerprint = legacyFingerprint(
|
||||
name = "searchBarOnClickListenerFingerprint",
|
||||
returnType = "Landroid/view/View;",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L", "L"),
|
||||
literals = listOf(searchBox, youTubeLogo),
|
||||
)
|
||||
|
||||
// ~ 19.36
|
||||
internal val searchBarOnClickListenerLegacyFingerprint = legacyFingerprint(
|
||||
name = "searchBarOnClickListenerLegacyFingerprint",
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("Landroid/view/View;", "L", "Z", "Z"),
|
||||
literals = listOf(searchBox, youTubeLogo),
|
||||
)
|
||||
|
||||
internal val setEnumMapFingerprint = legacyFingerprint(
|
||||
name = "setEnumMapFingerprint",
|
||||
literals = listOf(ytFillBell),
|
||||
|
|
|
|||
|
|
@ -2,38 +2,58 @@ package app.revanced.patches.youtube.general.navigation
|
|||
|
||||
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.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.spoof.guide.addClientOSVersionHook
|
||||
import app.revanced.patches.shared.spoof.guide.spoofClientGuideEndpointPatch
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_PATH
|
||||
import app.revanced.patches.youtube.utils.navigation.NavigationHook
|
||||
import app.revanced.patches.youtube.utils.navigation.addBottomBarContainerHook
|
||||
import app.revanced.patches.youtube.utils.navigation.hookNavigationButtonCreated
|
||||
import app.revanced.patches.youtube.utils.navigation.navigationBarHookPatch
|
||||
import app.revanced.patches.youtube.utils.navigation.navigationButtonsMethod
|
||||
import app.revanced.patches.youtube.utils.patch.PatchList.NAVIGATION_BAR_COMPONENTS
|
||||
import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater
|
||||
import app.revanced.patches.youtube.utils.playservice.is_19_28_or_greater
|
||||
import app.revanced.patches.youtube.utils.playservice.is_19_37_or_greater
|
||||
import app.revanced.patches.youtube.utils.playservice.is_20_06_or_greater
|
||||
import app.revanced.patches.youtube.utils.playservice.is_20_28_or_greater
|
||||
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.newContentCount
|
||||
import app.revanced.patches.youtube.utils.resourceid.newContentDot
|
||||
import app.revanced.patches.youtube.utils.resourceid.searchBox
|
||||
import app.revanced.patches.youtube.utils.resourceid.searchQuery
|
||||
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.ytOutlineLibrary
|
||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
||||
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||
import app.revanced.util.ResourceGroup
|
||||
import app.revanced.util.copyResources
|
||||
import app.revanced.util.copyXmlNode
|
||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
|
||||
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.indexOfFirstLiteralInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstStringInstruction
|
||||
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
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
|
||||
|
||||
private val navigationBarComponentsResourcePatch = resourcePatch(
|
||||
description = "navigationBarComponentsResourcePatch"
|
||||
|
|
@ -68,9 +88,27 @@ private val navigationBarComponentsResourcePatch = resourcePatch(
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
copyResources(
|
||||
"youtube/navigationbuttons",
|
||||
ResourceGroup(
|
||||
"layout",
|
||||
"empty_content_count.xml",
|
||||
"empty_content_dot.xml"
|
||||
)
|
||||
)
|
||||
|
||||
copyXmlNode(
|
||||
"youtube/navigationbuttons/host",
|
||||
"layout/image_with_text_tab.xml",
|
||||
"android.support.constraint.ConstraintLayout"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"$GENERAL_PATH/NavigationButtonsPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val navigationBarComponentsPatch = bytecodePatch(
|
||||
NAVIGATION_BAR_COMPONENTS.title,
|
||||
|
|
@ -83,6 +121,7 @@ val navigationBarComponentsPatch = bytecodePatch(
|
|||
settingsPatch,
|
||||
sharedResourceIdPatch,
|
||||
navigationBarHookPatch,
|
||||
spoofClientGuideEndpointPatch,
|
||||
versionCheckPatch,
|
||||
)
|
||||
|
||||
|
|
@ -98,7 +137,7 @@ val navigationBarComponentsPatch = bytecodePatch(
|
|||
if (is_19_25_or_greater) {
|
||||
translucentNavigationBarFingerprint.injectLiteralInstructionBooleanCall(
|
||||
TRANSLUCENT_NAVIGATION_BAR_FEATURE_FLAG,
|
||||
"$GENERAL_CLASS_DESCRIPTOR->enableTranslucentNavigationBar()Z"
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->enableTranslucentNavigationBar()Z"
|
||||
)
|
||||
|
||||
settingArray += "SETTINGS: TRANSLUCENT_NAVIGATION_BAR"
|
||||
|
|
@ -119,7 +158,7 @@ val navigationBarComponentsPatch = bytecodePatch(
|
|||
|
||||
addInstructions(
|
||||
targetIndex + 1, """
|
||||
invoke-static {v$register}, $GENERAL_CLASS_DESCRIPTOR->enableNarrowNavigationButton(Z)Z
|
||||
invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->enableNarrowNavigationButton(Z)Z
|
||||
move-result v$register
|
||||
"""
|
||||
)
|
||||
|
|
@ -131,24 +170,219 @@ val navigationBarComponentsPatch = bytecodePatch(
|
|||
|
||||
// region patch for hide navigation bar
|
||||
|
||||
addBottomBarContainerHook("$GENERAL_CLASS_DESCRIPTOR->hideNavigationBar(Landroid/view/View;)V")
|
||||
addBottomBarContainerHook("$EXTENSION_CLASS_DESCRIPTOR->hideNavigationBar(Landroid/view/View;)V")
|
||||
|
||||
// endregion
|
||||
|
||||
// region patch for hide navigation buttons
|
||||
|
||||
autoMotiveFingerprint.methodOrThrow().apply {
|
||||
val insertIndex = indexOfFirstStringInstructionOrThrow(ANDROID_AUTOMOTIVE_STRING) - 1
|
||||
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
// Swap Create and Notifications buttons
|
||||
addClientOSVersionHook(
|
||||
"patch_setClientOSNameByNavigationBarPatch",
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->getOSName()Ljava/lang/String;",
|
||||
is_20_06_or_greater,
|
||||
true
|
||||
)
|
||||
|
||||
val onClickListenerFingerprint = if (is_19_37_or_greater)
|
||||
searchBarOnClickListenerFingerprint
|
||||
else
|
||||
searchBarOnClickListenerLegacyFingerprint
|
||||
|
||||
onClickListenerFingerprint.methodOrThrow().apply {
|
||||
val searchBoxIdIndex = indexOfFirstLiteralInstructionOrThrow(searchBox)
|
||||
|
||||
val onClickMethodIndex = indexOfFirstInstructionOrThrow(searchBoxIdIndex) {
|
||||
val reference = getReference<MethodReference>()
|
||||
(opcode == Opcode.INVOKE_VIRTUAL || opcode == Opcode.INVOKE_DIRECT) &&
|
||||
reference?.returnType == "V" &&
|
||||
reference.parameterTypes.size == 2 &&
|
||||
reference.parameterTypes.firstOrNull() == "Landroid/view/View;" &&
|
||||
reference.parameterTypes[1].toString().startsWith("L")
|
||||
}
|
||||
|
||||
with (getWalkerMethod(onClickMethodIndex)) {
|
||||
val onClickListenerIndex =
|
||||
indexOfFirstInstructionOrThrow(Opcode.NEW_INSTANCE)
|
||||
val onClickListenerRegister =
|
||||
getInstruction<OneRegisterInstruction>(onClickListenerIndex).registerA
|
||||
|
||||
val viewIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "setOnClickListener"
|
||||
}
|
||||
val viewRegister =
|
||||
getInstruction<FiveRegisterInstruction>(viewIndex).registerC
|
||||
|
||||
addInstructionsWithLabels(
|
||||
viewIndex, """
|
||||
invoke-static {v$onClickListenerRegister}, $EXTENSION_CLASS_DESCRIPTOR->setSearchBarOnClickListener(Landroid/view/View${'$'}OnClickListener;)V
|
||||
if-eqz v$viewRegister, :ignore
|
||||
""",
|
||||
ExternalLabel("ignore", getInstruction(viewIndex + 1))
|
||||
)
|
||||
}
|
||||
|
||||
// invoke-direct or invoke-virtual
|
||||
val onClickMethodOpcode = getInstruction(onClickMethodIndex).opcode.name
|
||||
val onClickMethodReference =
|
||||
getInstruction<ReferenceInstruction>(onClickMethodIndex).reference
|
||||
|
||||
val (classRegister, objectRegister) =
|
||||
getInstruction<FiveRegisterInstruction>(
|
||||
onClickMethodIndex
|
||||
).let { i -> i.registerC to i.registerE }
|
||||
|
||||
fun getField(register: Int): FieldReference {
|
||||
val index =
|
||||
indexOfFirstInstructionReversedOrThrow(onClickMethodIndex) {
|
||||
opcode == Opcode.IGET_OBJECT &&
|
||||
(this as TwoRegisterInstruction).registerA == register
|
||||
}
|
||||
|
||||
return getInstruction<ReferenceInstruction>(index).reference as FieldReference
|
||||
}
|
||||
|
||||
fun getParameter(register: Int): Int {
|
||||
val index =
|
||||
indexOfFirstInstructionReversedOrThrow(onClickMethodIndex) {
|
||||
opcode.name.startsWith("move-object") &&
|
||||
(this as TwoRegisterInstruction).registerA == register
|
||||
}
|
||||
|
||||
return getInstruction<TwoRegisterInstruction>(index).registerB
|
||||
}
|
||||
|
||||
val smaliInstructionsPrefix = if (is_19_37_or_greater) {
|
||||
val classField = getField(classRegister)
|
||||
val objectField = getField(objectRegister)
|
||||
|
||||
"""
|
||||
move-object/from16 v0, p0
|
||||
iget-object v1, v0, $classField
|
||||
iget-object v3, v0, $objectField
|
||||
"""
|
||||
} else {
|
||||
val classParameter = getParameter(classRegister)
|
||||
val objectParameter = getParameter(objectRegister)
|
||||
|
||||
"""
|
||||
move-object/from16 v1, v$classParameter
|
||||
move-object/from16 v3, v$objectParameter
|
||||
"""
|
||||
}
|
||||
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {v$insertRegister}, $GENERAL_CLASS_DESCRIPTOR->switchCreateWithNotificationButton(Z)Z
|
||||
move-result v$insertRegister
|
||||
0, smaliInstructionsPrefix + """
|
||||
const/4 v2, 0x0
|
||||
$onClickMethodOpcode {v1, v2, v3}, $onClickMethodReference
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
val enumClass = with(imageEnumConstructorFingerprint.methodOrThrow()) {
|
||||
arrayOf(
|
||||
SEARCH_STRING to "search",
|
||||
SEARCH_CAIRO_STRING to "searchCairo",
|
||||
).map { (enumName, fieldName) ->
|
||||
val stringIndex = indexOfFirstStringInstruction(enumName)
|
||||
|
||||
if (stringIndex > -1) {
|
||||
val insertIndex =
|
||||
indexOfFirstInstructionOrThrow(stringIndex, Opcode.SPUT_OBJECT)
|
||||
val insertRegister =
|
||||
getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
insertIndex + 1,
|
||||
"sput-object v$insertRegister, $EXTENSION_CLASS_DESCRIPTOR->$fieldName:Ljava/lang/Enum;"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
definingClass
|
||||
}
|
||||
|
||||
navigationButtonsMethod.apply {
|
||||
findInstructionIndicesReversedOrThrow {
|
||||
opcode == Opcode.INVOKE_STATIC &&
|
||||
getReference<MethodReference>()?.name == NavigationHook.SET_LAST_APP_NAVIGATION_ENUM.methodName
|
||||
}.forEach { enumIndex ->
|
||||
val spanIndex = implementation!!.instructions.let {
|
||||
val subListIndex =
|
||||
it.subList(enumIndex, enumIndex + 20).indexOfFirst { instruction ->
|
||||
instruction.opcode == Opcode.INVOKE_STATIC &&
|
||||
instruction.getReference<MethodReference>()?.returnType == "Landroid/text/Spanned;"
|
||||
} + 1
|
||||
if (subListIndex > 0) {
|
||||
enumIndex + subListIndex
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
|
||||
if (spanIndex > 0) {
|
||||
val spanRegister =
|
||||
getInstruction<OneRegisterInstruction>(spanIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
spanIndex + 1, """
|
||||
invoke-static {v$spanRegister}, $EXTENSION_CLASS_DESCRIPTOR->changeSpanned(Landroid/text/Spanned;)Landroid/text/Spanned;
|
||||
move-result-object v$spanRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
val enumRegister =
|
||||
getInstruction<FiveRegisterInstruction>(enumIndex).registerC
|
||||
|
||||
addInstructions(
|
||||
enumIndex + 1, """
|
||||
invoke-static {v$enumRegister}, $EXTENSION_CLASS_DESCRIPTOR->changeIconType(Ljava/lang/Enum;)Ljava/lang/Enum;
|
||||
move-result-object v$enumRegister
|
||||
check-cast v$enumRegister, $enumClass
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pivotBarBuilderFingerprint.methodOrThrow().apply {
|
||||
mapOf(
|
||||
newContentCount to "getContentCountId",
|
||||
newContentDot to "getContentDotId"
|
||||
).forEach { (literal, methodName) ->
|
||||
val literalIndex = indexOfFirstLiteralInstructionOrThrow(literal)
|
||||
val viewIndex = indexOfFirstInstructionOrThrow(literalIndex - 1) {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "findViewById"
|
||||
}
|
||||
val viewInstruction = getInstruction<FiveRegisterInstruction>(viewIndex)
|
||||
|
||||
replaceInstruction(
|
||||
viewIndex,
|
||||
"invoke-static {v${viewInstruction.registerC}, v${viewInstruction.registerD}}, " +
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/view/View;I)Landroid/view/View;"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
actionBarSearchResultsFingerprint.methodOrThrow().apply {
|
||||
val searchQueryId = indexOfFirstLiteralInstructionOrThrow(searchQuery)
|
||||
|
||||
val castIndex = indexOfFirstInstructionOrThrow(searchQueryId) {
|
||||
opcode == Opcode.CHECK_CAST &&
|
||||
getReference<TypeReference>()?.type == "Landroid/widget/TextView;"
|
||||
}
|
||||
|
||||
val viewRegister = getInstruction<OneRegisterInstruction>(castIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
castIndex + 1,
|
||||
"invoke-static { v$viewRegister }, " +
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->searchQueryViewLoaded(Landroid/widget/TextView;)V",
|
||||
)
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region patch for hide navigation label
|
||||
|
|
@ -163,7 +397,7 @@ val navigationBarComponentsPatch = bytecodePatch(
|
|||
|
||||
addInstruction(
|
||||
targetIndex,
|
||||
"invoke-static {v$targetRegister}, $GENERAL_CLASS_DESCRIPTOR->hideNavigationLabel(Landroid/widget/TextView;)V"
|
||||
"invoke-static {v$targetRegister}, $EXTENSION_CLASS_DESCRIPTOR->hideNavigationLabel(Landroid/widget/TextView;)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -211,7 +445,7 @@ val navigationBarComponentsPatch = bytecodePatch(
|
|||
addInstructions(
|
||||
enumMapIndex + 1, """
|
||||
sget-object v$enumRegister, $cairoNotificationEnumReference
|
||||
invoke-static {v$enumMapRegister, v$enumRegister}, $GENERAL_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V
|
||||
invoke-static {v$enumMapRegister, v$enumRegister}, $EXTENSION_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
|
@ -222,7 +456,7 @@ val navigationBarComponentsPatch = bytecodePatch(
|
|||
|
||||
addInstructions(
|
||||
index + 1, """
|
||||
invoke-static {v$register}, $GENERAL_CLASS_DESCRIPTOR->getLibraryDrawableId(I)I
|
||||
invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->getLibraryDrawableId(I)I
|
||||
move-result v$register
|
||||
"""
|
||||
)
|
||||
|
|
@ -232,7 +466,7 @@ val navigationBarComponentsPatch = bytecodePatch(
|
|||
// endregion
|
||||
|
||||
// Hook navigation button created, in order to hide them.
|
||||
hookNavigationButtonCreated(GENERAL_CLASS_DESCRIPTOR)
|
||||
hookNavigationButtonCreated(EXTENSION_CLASS_DESCRIPTOR)
|
||||
|
||||
// region add settings
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package app.revanced.patches.youtube.general.toolbar
|
|||
import app.revanced.patches.youtube.utils.resourceid.actionBarRingo
|
||||
import app.revanced.patches.youtube.utils.resourceid.actionBarRingoBackground
|
||||
import app.revanced.patches.youtube.utils.resourceid.drawerContentView
|
||||
import app.revanced.patches.youtube.utils.resourceid.menuSearch
|
||||
import app.revanced.patches.youtube.utils.resourceid.p13nHeader
|
||||
import app.revanced.patches.youtube.utils.resourceid.seeMoreProceedingHeader
|
||||
import app.revanced.patches.youtube.utils.resourceid.voiceSearch
|
||||
|
|
@ -227,6 +228,26 @@ internal val searchBarParentFingerprint = legacyFingerprint(
|
|||
literals = listOf(voiceSearch),
|
||||
)
|
||||
|
||||
internal val toolbarSearchButtonFingerprint = legacyFingerprint(
|
||||
name = "toolbarSearchButtonFingerprint",
|
||||
returnType = "V",
|
||||
parameters = listOf("Landroid/view/MenuItem;"),
|
||||
customFingerprint = { method, _ ->
|
||||
indexOfShowAsActionInstruction(method) >= 0
|
||||
}
|
||||
)
|
||||
|
||||
internal fun indexOfShowAsActionInstruction(method: Method) =
|
||||
method.indexOfFirstInstructionReversed {
|
||||
getReference<MethodReference>()?.name == "setShowAsAction"
|
||||
}
|
||||
|
||||
internal val toolbarSearchButtonLabelFingerprint = legacyFingerprint(
|
||||
name = "toolbarSearchButtonLabelFingerprint",
|
||||
returnType = "Ljava/lang/CharSequence;",
|
||||
literals = listOf(menuSearch),
|
||||
)
|
||||
|
||||
internal val voiceInputControllerParentFingerprint = legacyFingerprint(
|
||||
name = "voiceInputControllerParentFingerprint",
|
||||
returnType = "V",
|
||||
|
|
|
|||
|
|
@ -256,6 +256,25 @@ val toolBarComponentsPatch = bytecodePatch(
|
|||
|
||||
// endregion
|
||||
|
||||
// region patch for hide search button
|
||||
|
||||
hookToolBar("$GENERAL_CLASS_DESCRIPTOR->hideSearchButton")
|
||||
|
||||
toolbarSearchButtonFingerprint
|
||||
.methodOrThrow(toolbarSearchButtonLabelFingerprint)
|
||||
.apply {
|
||||
val index = indexOfShowAsActionInstruction(this)
|
||||
val instruction = getInstruction<FiveRegisterInstruction>(index)
|
||||
|
||||
replaceInstruction(
|
||||
index,
|
||||
"invoke-static {v${instruction.registerC}, v${instruction.registerD}}, " +
|
||||
"$GENERAL_CLASS_DESCRIPTOR->hideSearchButton(Landroid/view/MenuItem;I)V"
|
||||
)
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region patch for hide search term thumbnail
|
||||
|
||||
if (!is_20_15_or_greater) {
|
||||
|
|
|
|||
|
|
@ -378,6 +378,7 @@ private val rvxPreferenceKey = mapOf(
|
|||
"revanced_hide_toolbar_cast_button" to "revanced_hide_player_cast_button",
|
||||
"revanced_hide_toolbar_create_button" to "revanced_hide_navigation_create_button",
|
||||
"revanced_hide_toolbar_notification_button" to "notification_key",
|
||||
"revanced_hide_toolbar_search_button" to "revanced_hide_shorts_shelf_search",
|
||||
"revanced_hide_visual_spacers" to "M 215.38 495.38 Q 208.85 495.38 204.42 490.9 Q 200 486.41 200 479.78 Q 200 473.15 204.42 468.88 Q 208.85 464.62 215.38 464.62 L 744.62 464.62 Q 751.15 464.62 755.58 469.1 Q 760 473.59 760 480.22 Q 760 486.85 755.58 491.12 Q 751.15 495.38 744.62 495.38 L 215.38 495.38 Z",
|
||||
"revanced_language" to "M 480 840 Q 405.23 840 339.54 811.58 Q 273.85 783.15 224.85 734.54 Q 175.85 685.92 147.92 620.12 Q 120 554.31 120 478.77 Q 120 404 147.92 338.42 Q 175.85 272.85 224.85 224.23 Q 273.85 175.62 339.54 147.81 Q 405.23 120 480 120 Q 554.77 120 620.46 147.81 Q 686.15 175.62 735.15 224.23 Q 784.15 272.85 812.08 338.42 Q 840 404 840 478.77 Q 840 554.31 812.08 620.12 Q 784.15 685.92 735.15 734.54 Q 686.15 783.15 620.46 811.58 Q 554.77 840 480 840 Z M 480 811.23 Q 519.62 766.77 544.27 719.12 Q 568.92 671.46 584.69 609 L 375.54 609 Q 391.85 673.62 416.5 721.23 Q 441.15 768.85 480 811.23 Z M 438.08 806.92 Q 406.92 772 381.62 719.15 Q 356.31 666.31 343.54 609 L 175.08 609 Q 213.85 693.08 280 742.42 Q 346.15 791.77 438.08 806.92 Z M 522.92 806.69 Q 608 794.46 677.42 742.31 Q 746.85 690.15 784.92 609 L 616.69 609 Q 599.85 667.62 575.04 719.69 Q 550.23 771.77 522.92 806.69 Z M 165.85 578.23 L 337.92 578.23 Q 333.38 550.46 331.73 525.88 Q 330.08 501.31 330.08 478.77 Q 330.08 455.31 331.85 431.58 Q 333.62 407.85 338.15 381.54 L 165.85 381.54 Q 158.08 404 154.42 428.38 Q 150.77 452.77 150.77 478.77 Q 150.77 505.54 154.42 530.27 Q 158.08 555 165.85 578.23 Z M 369.15 578.23 L 591.08 578.23 Q 595.85 548.77 597.62 525.81 Q 599.38 502.85 599.38 478.77 Q 599.38 455.69 597.62 433.35 Q 595.85 411 591.08 381.54 L 369.15 381.54 Q 364.38 411 362.62 433.35 Q 360.85 455.69 360.85 478.77 Q 360.85 502.85 362.62 525.81 Q 364.38 548.77 369.15 578.23 Z M 621.85 578.23 L 794.15 578.23 Q 801.92 555 805.58 530.27 Q 809.23 505.54 809.23 478.77 Q 809.23 452.77 805.58 428.38 Q 801.92 404 794.15 381.54 L 622.85 381.54 Q 626.62 412.69 628.38 435.81 Q 630.15 458.92 630.15 478.77 Q 630.15 501.54 628.27 525.27 Q 626.38 549 621.85 578.23 Z M 616.46 350.77 L 784.92 350.77 Q 747.31 266.38 679.81 215.38 Q 612.31 164.38 521.92 152.31 Q 553.08 190.85 577.5 241.92 Q 601.92 293 616.46 350.77 Z M 375.54 350.77 L 585.69 350.77 Q 570.08 290.85 543.69 240.19 Q 517.31 189.54 480 149.23 Q 444.15 184.69 419.46 232.54 Q 394.77 280.38 375.54 350.77 Z M 175.08 350.77 L 343.77 350.77 Q 357.85 293.69 381.77 243.12 Q 405.69 192.54 437.08 152.54 Q 346.69 165.38 279.92 215.77 Q 213.15 266.15 175.08 350.77 Z",
|
||||
"revanced_miniplayer_type" to "offline_key",
|
||||
|
|
|
|||
|
|
@ -347,6 +347,9 @@ internal val quickSeekOverlayFingerprint = legacyFingerprint(
|
|||
literals = listOf(darkBackground, tapBloomView),
|
||||
)
|
||||
|
||||
/**
|
||||
* YouTube 18.39 - 20.02
|
||||
*/
|
||||
internal val seekEduContainerFingerprint = legacyFingerprint(
|
||||
name = "seekEduContainerFingerprint",
|
||||
returnType = "V",
|
||||
|
|
|
|||
|
|
@ -758,10 +758,11 @@ val playerComponentsPatch = bytecodePatch(
|
|||
|
||||
// endregion
|
||||
|
||||
// region patch for hide seek message
|
||||
// region patch for hide seek message (Removed in YouTube 20.03+)
|
||||
|
||||
seekEduContainerFingerprint.methodOrThrow().apply {
|
||||
val (register, condition, insertIndex) = when {
|
||||
if (!is_20_03_or_greater) {
|
||||
seekEduContainerFingerprint.methodOrThrow().apply {
|
||||
val (register, condition, insertIndex) = when {
|
||||
is_20_18_or_greater && !is_20_19_or_greater -> {
|
||||
Triple("v2", "if-nez", 0)
|
||||
}
|
||||
|
|
@ -784,35 +785,35 @@ val playerComponentsPatch = bytecodePatch(
|
|||
return-void
|
||||
""",
|
||||
ExternalLabel("default", labelInstruction)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Removed in YouTube 20.02+
|
||||
if (!is_20_02_or_greater) {
|
||||
youtubeControlsOverlayFingerprint.methodOrThrow().apply {
|
||||
val insertIndex =
|
||||
indexOfFirstLiteralInstructionOrThrow(seekUndoEduOverlayStub)
|
||||
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
if (!is_20_02_or_greater) {
|
||||
youtubeControlsOverlayFingerprint.methodOrThrow().apply {
|
||||
val insertIndex =
|
||||
indexOfFirstLiteralInstructionOrThrow(seekUndoEduOverlayStub)
|
||||
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
val onClickListenerIndex = indexOfFirstInstructionOrThrow(insertIndex) {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "setOnClickListener"
|
||||
}
|
||||
val constComponent = getFirstLiteralComponent(insertIndex, onClickListenerIndex - 1)
|
||||
val onClickListenerIndex = indexOfFirstInstructionOrThrow(insertIndex) {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "setOnClickListener"
|
||||
}
|
||||
val constComponent = getFirstLiteralComponent(insertIndex, onClickListenerIndex - 1)
|
||||
|
||||
if (constComponent.isNotEmpty()) {
|
||||
addInstruction(
|
||||
onClickListenerIndex + 2,
|
||||
constComponent
|
||||
)
|
||||
}
|
||||
addInstructionsWithLabels(
|
||||
insertIndex, """
|
||||
if (constComponent.isNotEmpty()) {
|
||||
addInstruction(
|
||||
onClickListenerIndex + 2,
|
||||
constComponent
|
||||
)
|
||||
}
|
||||
addInstructionsWithLabels(
|
||||
insertIndex, """
|
||||
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->hideSeekUndoMessage()Z
|
||||
move-result v$insertRegister
|
||||
if-nez v$insertRegister, :default
|
||||
""", ExternalLabel("default", getInstruction(onClickListenerIndex + 1))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ internal const val EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR =
|
|||
private lateinit var bottomBarContainerMethod: MutableMethod
|
||||
private var bottomBarContainerOffset = 0
|
||||
|
||||
lateinit var navigationButtonsMethod: MutableMethod
|
||||
private set
|
||||
|
||||
lateinit var hookNavigationButtonCreated: (String) -> Unit
|
||||
|
||||
val navigationBarHookPatch = bytecodePatch(
|
||||
|
|
@ -66,6 +69,8 @@ val navigationBarHookPatch = bytecodePatch(
|
|||
}
|
||||
|
||||
initializeButtonsFingerprint.methodOrThrow(pivotBarConstructorFingerprint).apply {
|
||||
navigationButtonsMethod = this
|
||||
|
||||
// Hook the current navigation bar enum value. Note, the 'You' tab does not have an enum value.
|
||||
val navigationEnumClassName = navigationEnumFingerprint.mutableClassOrThrow().type
|
||||
addHook(NavigationHook.SET_LAST_APP_NAVIGATION_ENUM) {
|
||||
|
|
@ -147,7 +152,7 @@ fun addBottomBarContainerHook(descriptor: String) {
|
|||
}
|
||||
}
|
||||
|
||||
private enum class NavigationHook(val methodName: String, val parameters: String) {
|
||||
internal enum class NavigationHook(val methodName: String, val parameters: String) {
|
||||
SET_LAST_APP_NAVIGATION_ENUM("setLastAppNavigationEnum", "Ljava/lang/Enum;"),
|
||||
NAVIGATION_TAB_LOADED("navigationTabLoaded", "Landroid/view/View;"),
|
||||
NAVIGATION_IMAGE_RESOURCE_TAB_LOADED(
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ var is_19_34_or_greater = false
|
|||
private set
|
||||
var is_19_36_or_greater = false
|
||||
private set
|
||||
var is_19_37_or_greater = false
|
||||
private set
|
||||
var is_19_41_or_greater = false
|
||||
private set
|
||||
var is_19_42_or_greater = false
|
||||
|
|
@ -75,6 +77,8 @@ var is_20_04_or_greater = false
|
|||
private set
|
||||
var is_20_05_or_greater = false
|
||||
private set
|
||||
var is_20_06_or_greater = false
|
||||
private set
|
||||
var is_20_07_or_greater = false
|
||||
private set
|
||||
var is_20_09_or_greater = false
|
||||
|
|
@ -147,6 +151,7 @@ val versionCheckPatch = resourcePatch(
|
|||
is_19_32_or_greater = isGreaterThan(243305000)
|
||||
is_19_34_or_greater = isGreaterThan(243499000)
|
||||
is_19_36_or_greater = isGreaterThan(243705000)
|
||||
is_19_37_or_greater = isGreaterThan(243805000)
|
||||
is_19_41_or_greater = isGreaterThan(244205000)
|
||||
is_19_42_or_greater = isGreaterThan(244305000)
|
||||
is_19_43_or_greater = isGreaterThan(244405000)
|
||||
|
|
@ -158,6 +163,7 @@ val versionCheckPatch = resourcePatch(
|
|||
is_20_03_or_greater = isGreaterThan(250405000)
|
||||
is_20_04_or_greater = isGreaterThan(250505000)
|
||||
is_20_05_or_greater = isGreaterThan(250605000)
|
||||
is_20_06_or_greater = isGreaterThan(250705000)
|
||||
is_20_07_or_greater = isGreaterThan(250805000)
|
||||
is_20_09_or_greater = isGreaterThan(251006000)
|
||||
is_20_10_or_greater = isGreaterThan(251105000)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ var actionBarRingo = -1L
|
|||
private set
|
||||
var actionBarRingoBackground = -1L
|
||||
private set
|
||||
var actionBarSearchResultsViewMic = -1L
|
||||
private set
|
||||
var adAttribution = -1L
|
||||
private set
|
||||
var appearance = -1L
|
||||
|
|
@ -128,6 +130,8 @@ var mdxSeamlessTVSignInDrawerFragmentTitle = -1L
|
|||
private set
|
||||
var menuItemView = -1L
|
||||
private set
|
||||
var menuSearch = -1L
|
||||
private set
|
||||
var miniplayerMaxSize = -1L
|
||||
private set
|
||||
var modernMiniPlayerClose = -1L
|
||||
|
|
@ -142,6 +146,10 @@ var modernMiniPlayerRewindButton = -1L
|
|||
private set
|
||||
var musicAppDeeplinkButtonView = -1L
|
||||
private set
|
||||
var newContentCount = -1L
|
||||
private set
|
||||
var newContentDot = -1L
|
||||
private set
|
||||
var notificationBigPictureIconWidth = -1L
|
||||
private set
|
||||
var offlineActionsVideoDeletedUndoSnackbarText = -1L
|
||||
|
|
@ -196,6 +204,10 @@ var rightComment = -1L
|
|||
private set
|
||||
var scrimOverlay = -1L
|
||||
private set
|
||||
var searchBox = -1L
|
||||
private set
|
||||
var searchQuery = -1L
|
||||
private set
|
||||
var seekEasyHorizontalTouchOffsetToStartScrubbing = -1L
|
||||
private set
|
||||
var seekUndoEduOverlayStub = -1L
|
||||
|
|
@ -276,6 +288,7 @@ internal val sharedResourceIdPatch = resourcePatch(
|
|||
accountSwitcherAccessibility = getResourceId(STRING, "account_switcher_accessibility_label")
|
||||
actionBarRingo = getResourceId(LAYOUT, "action_bar_ringo")
|
||||
actionBarRingoBackground = getResourceId(LAYOUT, "action_bar_ringo_background")
|
||||
actionBarSearchResultsViewMic = getResourceId(LAYOUT, "action_bar_search_results_view_mic")
|
||||
adAttribution = getResourceId(ID, "ad_attribution")
|
||||
appearance = getResourceId(STRING, "app_theme_appearance_dark")
|
||||
appRelatedEndScreenResults = getResourceId(LAYOUT, "app_related_endscreen_results")
|
||||
|
|
@ -333,6 +346,7 @@ internal val sharedResourceIdPatch = resourcePatch(
|
|||
mdxSeamlessTVSignInDrawerFragmentTitle =
|
||||
getResourceId(STRING, "mdx_seamless_tv_sign_in_drawer_fragment_title")
|
||||
menuItemView = getResourceId(ID, "menu_item_view")
|
||||
menuSearch = getResourceId(STRING, "menu_search")
|
||||
miniplayerMaxSize = getResourceId(DIMEN, "miniplayer_max_size")
|
||||
modernMiniPlayerClose = getResourceId(ID, "modern_miniplayer_close")
|
||||
modernMiniPlayerExpand = getResourceId(ID, "modern_miniplayer_expand")
|
||||
|
|
@ -341,6 +355,8 @@ internal val sharedResourceIdPatch = resourcePatch(
|
|||
getResourceId(ID, "modern_miniplayer_overlay_action_button")
|
||||
modernMiniPlayerRewindButton = getResourceId(ID, "modern_miniplayer_rewind_button")
|
||||
musicAppDeeplinkButtonView = getResourceId(ID, "music_app_deeplink_button_view")
|
||||
newContentCount = getResourceId(ID, "new_content_count")
|
||||
newContentDot = getResourceId(ID, "new_content_dot")
|
||||
notificationBigPictureIconWidth =
|
||||
getResourceId(DIMEN, "notification_big_picture_icon_width")
|
||||
offlineActionsVideoDeletedUndoSnackbarText =
|
||||
|
|
@ -373,6 +389,8 @@ internal val sharedResourceIdPatch = resourcePatch(
|
|||
relatedChipCloudMargin = getResourceId(LAYOUT, "related_chip_cloud_reduced_margins")
|
||||
rightComment = getResourceId(DRAWABLE, "ic_right_comment_32c")
|
||||
scrimOverlay = getResourceId(ID, "scrim_overlay")
|
||||
searchBox = getResourceId(ID, "search_box")
|
||||
searchQuery = getResourceId(ID, "search_query")
|
||||
seekEasyHorizontalTouchOffsetToStartScrubbing =
|
||||
getResourceId(DIMEN, "seek_easy_horizontal_touch_offset_to_start_scrubbing")
|
||||
seekUndoEduOverlayStub = getResourceId(ID, "seek_undo_edu_overlay_stub")
|
||||
|
|
|
|||
|
|
@ -544,7 +544,7 @@ Hạn chế:
|
|||
• Đôi khi phụ đề hiển thị ở phía trên của trình phát thay vì ở phía dưới như thường lệ."</string>
|
||||
<string name="revanced_spoof_player_parameter_title">Giả mạo thông số trình phát</string>
|
||||
<string name="revanced_spoof_streaming_data_client_entry_android_creator">Android Studio</string>
|
||||
<string name="revanced_spoof_streaming_data_client_entry_android_no_sdk">Android No SDK</string>
|
||||
<string name="revanced_spoof_streaming_data_client_entry_android_no_sdk">Android Không SDK</string>
|
||||
<string name="revanced_spoof_streaming_data_client_entry_android_vr">Android VR</string>
|
||||
<string name="revanced_spoof_streaming_data_client_entry_android_vr_auth">Android VR Auth (Cần thao tác)</string>
|
||||
<string name="revanced_spoof_streaming_data_client_entry_mweb">Mobile Web</string>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout android:background="?selectableItemBackgroundBorderless" android:layout_width="0.0dip" android:layout_height="fill_parent" android:minWidth="@dimen/pivot_bar_tab_min_width" android:layout_weight="1.0"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:yt="http://schemas.android.com/apk/res-auto">
|
||||
<ViewStub android:id="@+id/empty_content_dot" android:layout="@layout/empty_content_dot" android:inflatedId="@+id/empty_content_dot" android:layout_width="0.0dip" android:layout_height="0.0dip" />
|
||||
<ViewStub android:id="@+id/empty_content_count" android:layout="@layout/empty_content_count" android:inflatedId="@+id/empty_content_count" android:layout_width="0.0dip" android:layout_height="0.0dip" />
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView android:textSize="0.0dip" android:textColor="@android:color/transparent" android:gravity="center" android:id="@+id/empty_content_count" android:background="@android:color/transparent" android:visibility="gone" android:paddingTop="0.0dip" android:paddingBottom="0.0dip" android:layout_width="0.0dip" android:layout_height="0.0dip" android:minWidth="0.0dip" android:includeFontPadding="false" android:paddingStart="0.0dip" android:paddingEnd="0.0dip"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" />
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<View android:id="@+id/empty_content_dot" android:background="@android:color/transparent" android:layout_width="0.0dip" android:layout_height="0.0dip" android:contentDescription=""
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" />
|
||||
|
|
@ -413,6 +413,18 @@
|
|||
<item>MINIMAL</item>
|
||||
<item>TABLET</item>
|
||||
</string-array>
|
||||
<string-array name="revanced_replace_navigation_button_target_entries">
|
||||
<item>@string/revanced_replace_navigation_button_target_entry_home</item>
|
||||
<item>@string/revanced_replace_navigation_button_target_entry_shorts</item>
|
||||
<item>@string/revanced_replace_navigation_button_target_entry_subscriptions</item>
|
||||
<item>@string/revanced_replace_navigation_button_target_entry_notifications</item>
|
||||
</string-array>
|
||||
<string-array name="revanced_replace_navigation_button_target_entry_values">
|
||||
<item>HOME</item>
|
||||
<item>SHORTS</item>
|
||||
<item>SUBSCRIPTIONS</item>
|
||||
<item>NOTIFICATIONS</item>
|
||||
</string-array>
|
||||
<string-array name="revanced_return_youtube_username_display_format_entries">
|
||||
<item>@string/revanced_return_youtube_username_display_format_username_only</item>
|
||||
<item>@string/revanced_return_youtube_username_display_format_username_handle</item>
|
||||
|
|
|
|||
|
|
@ -1373,6 +1373,11 @@ Side effect: Official headers in search results will be hidden."</string>
|
|||
<string name="revanced_hide_toolbar_notification_button_summary_off">Notifications button is shown.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_summary_on">Notifications button is hidden.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_title">Hide Notifications button</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_off">Search button is shown.</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_on">"Search button is hidden.
|
||||
|
||||
This setting may not work if the wide search bar is enabled."</string>
|
||||
<string name="revanced_hide_toolbar_search_button_title">Hide Search button</string>
|
||||
<string name="revanced_hide_transcript_section_summary_off">Transcript section is shown.</string>
|
||||
<string name="revanced_hide_transcript_section_summary_on">Transcript section is hidden.</string>
|
||||
<string name="revanced_hide_transcript_section_title">Hide Transcript section</string>
|
||||
|
|
@ -1921,6 +1926,13 @@ This does not bypass the age restriction. It just accepts it automatically."</st
|
|||
<string name="revanced_replace_channel_handle_summary_off">Channel handle is used.</string>
|
||||
<string name="revanced_replace_channel_handle_summary_on">Channel name is used.</string>
|
||||
<string name="revanced_replace_channel_handle_title">Replace channel handle</string>
|
||||
<string name="revanced_replace_navigation_button_summary">Replaces the navigation button with the Search button.</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_home">Home</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_notifications">Notifications</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_shorts">Shorts</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_subscriptions">Subscriptions</string>
|
||||
<string name="revanced_replace_navigation_button_target_title">Replace navigation button</string>
|
||||
<string name="revanced_replace_navigation_button_title">Replace navigation button</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_off">Tap to show the remaining time.</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_on">Tap to open playback speed or video quality flyout menu.</string>
|
||||
<string name="revanced_replace_time_stamp_action_title">Replace timestamp action</string>
|
||||
|
|
@ -2360,6 +2372,7 @@ Limitation: Video title disappears when clicked."</string>
|
|||
<string name="revanced_spoof_app_version_target_entry_19_28_42">19.28.42 - Restore old playlist header</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_19_33_37">19.33.37 - Restore old playback speed flyout panel</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_05_46">20.05.46 - Restore Transcript functionality</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_13_41">20.13.41 - Restore non collapsed video action bar</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_title">Spoof app version target</string>
|
||||
<string name="revanced_spoof_app_version_target_invalid_toast">Invalid spoof app version: %s.</string>
|
||||
<string name="revanced_spoof_app_version_target_summary">Type the spoof app version target.</string>
|
||||
|
|
@ -2710,15 +2723,9 @@ Adjust volume by swiping vertically on the right side of the screen."</string>
|
|||
• Disabling this setting loads more ads from the server side.
|
||||
• You should disable this setting to make video ads visible."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Create button is not switched with Notifications button.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Create button is switched with Notifications button.
|
||||
|
||||
Note: Enabling this also forcibly hides video ads."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">Create button is switched with Notifications button.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Swap Create and Notifications buttons</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Disabling this might load more ads from the server.
|
||||
|
||||
Also, ads will no longer be blocked in Shorts.
|
||||
|
||||
If this setting do not take effect, try switching to Incognito mode."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">If this setting do not take effect, try switching to Incognito mode.</string>
|
||||
<string name="revanced_theme_default">Stock</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Warning</string>
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@
|
|||
<!-- Translation Exception -->
|
||||
<string name="revanced_spoof_streaming_data_side_effects_tv_embedded">@string/revanced_spoof_streaming_data_side_effects_tv</string>
|
||||
<string name="revanced_spoof_streaming_data_side_effects_tv_legacy">@string/revanced_spoof_streaming_data_side_effects_tv</string>
|
||||
<string name="revanced_spoof_streaming_data_side_effects_web_legacy">@string/revanced_spoof_streaming_data_side_effects_tv</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@
|
|||
|
||||
<!-- SETTINGS: HIDE_NAVIGATION_COMPONENTS
|
||||
<SwitchPreference android:title="@string/revanced_hide_navigation_bar_title" android:key="revanced_hide_navigation_bar" android:summaryOn="@string/revanced_hide_navigation_bar_summary_on" android:summaryOff="@string/revanced_hide_navigation_bar_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_replace_navigation_button_title" android:key="revanced_replace_navigation_button" android:summary="@string/revanced_replace_navigation_button_summary" />
|
||||
<app.revanced.extension.shared.settings.preference.CustomDialogListPreference android:entries="@array/revanced_replace_navigation_button_target_entries" android:title="@string/revanced_replace_navigation_button_target_title" android:key="revanced_replace_navigation_button_target" android:entryValues="@array/revanced_replace_navigation_button_target_entry_values" />
|
||||
</PreferenceScreen>SETTINGS: HIDE_NAVIGATION_COMPONENTS -->
|
||||
|
||||
<!-- SETTINGS: HIDE_LAYOUT_COMPONENTS
|
||||
|
|
@ -103,6 +105,7 @@
|
|||
<SwitchPreference android:title="@string/revanced_hide_toolbar_cast_button_title" android:key="revanced_hide_toolbar_cast_button" android:summaryOn="@string/revanced_hide_toolbar_cast_button_summary_on" android:summaryOff="@string/revanced_hide_toolbar_cast_button_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_hide_toolbar_create_button_title" android:key="revanced_hide_toolbar_create_button" android:summaryOn="@string/revanced_hide_toolbar_create_button_summary_on" android:summaryOff="@string/revanced_hide_toolbar_create_button_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_hide_toolbar_notification_button_title" android:key="revanced_hide_toolbar_notification_button" android:summaryOn="@string/revanced_hide_toolbar_notification_button_summary_on" android:summaryOff="@string/revanced_hide_toolbar_notification_button_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_hide_toolbar_search_button_title" android:key="revanced_hide_toolbar_search_button" android:summaryOn="@string/revanced_hide_toolbar_search_button_summary_on" android:summaryOff="@string/revanced_hide_toolbar_search_button_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_hide_search_term_thumbnail_title" android:key="revanced_hide_search_term_thumbnail" android:summaryOn="@string/revanced_hide_search_term_thumbnail_summary_on" android:summaryOff="@string/revanced_hide_search_term_thumbnail_summary_off" />SETTINGS: TOOLBAR_COMPONENTS -->
|
||||
|
||||
<!-- SETTINGS: HIDE_IMAGE_SEARCH_BUTTON
|
||||
|
|
@ -618,9 +621,7 @@
|
|||
<SwitchPreference android:title="@string/revanced_hide_info_panel_title" android:key="revanced_hide_info_panel" android:summaryOn="@string/revanced_hide_info_panel_summary_on" android:summaryOff="@string/revanced_hide_info_panel_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_hide_medical_panel_title" android:key="revanced_hide_medical_panel" android:summaryOn="@string/revanced_hide_medical_panel_summary_on" android:summaryOff="@string/revanced_hide_medical_panel_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_hide_seek_message_title" android:key="revanced_hide_seek_message" android:summaryOn="@string/revanced_hide_seek_message_summary_on" android:summaryOff="@string/revanced_hide_seek_message_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_hide_seek_undo_message_title" android:key="revanced_hide_seek_undo_message" android:summaryOn="@string/revanced_hide_seek_undo_message_summary_on" android:summaryOff="@string/revanced_hide_seek_undo_message_summary_off" />SETTINGS: PLAYER_COMPONENTS -->
|
||||
|
||||
<!-- SETTINGS: PLAYER_COMPONENTS
|
||||
<SwitchPreference android:title="@string/revanced_hide_seek_undo_message_title" android:key="revanced_hide_seek_undo_message" android:summaryOn="@string/revanced_hide_seek_undo_message_summary_on" android:summaryOff="@string/revanced_hide_seek_undo_message_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_hide_suggested_actions_title" android:key="revanced_hide_suggested_actions" android:summaryOn="@string/revanced_hide_suggested_actions_summary_on" android:summaryOff="@string/revanced_hide_suggested_actions_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_hide_timed_reactions_title" android:key="revanced_hide_timed_reactions" android:summaryOn="@string/revanced_hide_timed_reactions_summary_on" android:summaryOff="@string/revanced_hide_timed_reactions_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_hide_zoom_overlay_title" android:key="revanced_hide_zoom_overlay" android:summaryOn="@string/revanced_hide_zoom_overlay_summary_on" android:summaryOff="@string/revanced_hide_zoom_overlay_summary_off" />
|
||||
|
|
|
|||
|
|
@ -1347,6 +1347,11 @@
|
|||
<string name="revanced_hide_toolbar_notification_button_summary_off">يتم عرض زر الإشعارات.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_summary_on">تم إخفاء زر الإشعارات.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_title">إخفاء زر الإشعارات</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_off">يتم عرض زر البحث.</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_on">"تم إخفاء زر البحث.
|
||||
|
||||
قد لا يعمل هذا الإعداد إذا تم تمكين شريط البحث العريض."</string>
|
||||
<string name="revanced_hide_toolbar_search_button_title">إخفاء زر البحث</string>
|
||||
<string name="revanced_hide_transcript_section_summary_off">يتم عرض قسم النص.</string>
|
||||
<string name="revanced_hide_transcript_section_summary_on">تم إخفاء قسم النص.</string>
|
||||
<string name="revanced_hide_transcript_section_title">إخفاء قسم النص</string>
|
||||
|
|
@ -1849,6 +1854,13 @@
|
|||
<string name="revanced_replace_channel_handle_summary_off">يتم استخدام الاسم المعرِّف.</string>
|
||||
<string name="revanced_replace_channel_handle_summary_on">يتم استخدام اسم القناة.</string>
|
||||
<string name="revanced_replace_channel_handle_title">استبدال معالج القناة</string>
|
||||
<string name="revanced_replace_navigation_button_summary">تبديل زر التنقل بزر البحث.</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_home">الصفحة الرئيسية</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_notifications">الإشعارات</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_shorts">Shorts</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_subscriptions">الاشتراكات</string>
|
||||
<string name="revanced_replace_navigation_button_target_title">تغيير زر التنقل</string>
|
||||
<string name="revanced_replace_navigation_button_title">استبدال زر التنقل</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_off">انقر لعرض الوقت المتبقي.</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_on">انقر لفتح القائمة المنبثقة لسرعة التشغيل أو جودة الفيديو.</string>
|
||||
<string name="revanced_replace_time_stamp_action_title">استبدال إجراء الطابع الزمني</string>
|
||||
|
|
@ -2273,6 +2285,7 @@
|
|||
<string name="revanced_spoof_app_version_target_entry_19_28_42">19.28.42 - استعادة علامة قائمة التشغيل القديمة</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_19_33_37">19.33.37 - استعادة لوحة التحكم القديمة لسرعة التشغيل</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_05_46">20.05.46 - استعادة وظيفة النسخ</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_13_41">\"20.13.41 - استعاده عرض شريط إجراءات الفيديو بالكامل</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_title">الهدف من خِداع إصدار التطبيق</string>
|
||||
<string name="revanced_spoof_app_version_target_invalid_toast">إصدار التطبيق الوهمي غير صالح: %s.</string>
|
||||
<string name="revanced_spoof_app_version_target_summary">اكتب هدف إصدار التطبيق الوهمي.</string>
|
||||
|
|
@ -2591,15 +2604,9 @@ AVC لديه حد أقصى للدقة 1080p، لا يتوفر ترميز الص
|
|||
• يؤدي تعطيل هذا الإعداد إلى تحميل المزيد من الإعلانات من جانب الخادم.
|
||||
• يجب عليك تعطيل هذا الإعداد لجعل إعلانات الفيديو مرئية."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">لا يتم تبديل زر الإنشاء بزر الإشعارات.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"تم تبديل زر الإنشاء بـزر الإشعارات.
|
||||
|
||||
ملاحظة: يؤدي تمكين هذا أيضًا إلى إخفاء إعلانات الفيديو بالقوة."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">يتم تبديل زر الإنشاء بزر الإشعارات.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">تبديل أزرار الإنشاء و الإشعارات</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"قد يؤدي تعطيل هذا إلى تحميل المزيد من الإعلانات من الخادم.
|
||||
|
||||
كما لن يتم حظر الإعلانات في فيديوهات Shorts بعد الآن.
|
||||
|
||||
إذا لم يتم تفعيل هذا الإعداد، فحاول التبديل إلى وضع التصفح المتخفي."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">إذا لم يكن هذا الإعداد ساري المفعول، جرّب التبديل إلى وضع التصفّح المتخفي.</string>
|
||||
<string name="revanced_theme_default">الإفتراضي</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">موسيقى RVX</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">تحذير</string>
|
||||
|
|
|
|||
|
|
@ -1870,15 +1870,13 @@ AVC има максимална разделителна способност о
|
|||
• Деактивирането на тази настройка зарежда повече реклами от страната на сървъра.
|
||||
• Трябва да деактивирате тази настройка, за да направите видео рекламите видими."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Бутоните \"Създаване\" и \"Известия\" не са разменени.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Бутонът за създаване се заменя с бутона за известия
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Бутонът за създаване е сменен с бутона Известия
|
||||
|
||||
Забележка: Активирането на тази опция също скрива видеореклами."</string>
|
||||
Забележка: Активирането на това също принудително скрива видео рекламите"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Разменете бутоните „Създаване“ с „Известия“</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Деактивирането на тази настройка може да доведе до зареждане на повече реклами от сървъра.
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Деактивирането на тази настройка също ще деактивира блокирането на рекламите за Shorts.
|
||||
|
||||
Освен това рекламите може да се показват в Shorts.
|
||||
|
||||
Ако деактивирането не влезе в сила, опитайте да превключите към режим „инкогнито“."</string>
|
||||
Ако промяната на тази настройка не влезе в сила, опитайте да превключите в режим „инкогнито“."</string>
|
||||
<string name="revanced_theme_default">По подразбиране</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Внимание</string>
|
||||
|
|
|
|||
|
|
@ -2547,15 +2547,13 @@ Adjust volume by swiping vertically on the right side of the screen."</string>
|
|||
• Deaktivieren dieser Einstellung lädt mehr Werbung von der Serverseite.
|
||||
• Sie sollten diese Einstellung deaktivieren, um Video-Werbung sichtbar zu machen."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Erstellen-Button ist nicht mit Benachrichtigungs-Button getauscht.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Die Schaltfläche \"Erstellen\" wird mit der Schaltfläche \"Benachrichtigungen\" vertauscht.
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Die Schaltfläche \"Erstellen\" wird mit der Schaltfläche \"Benachrichtigungen\" vertauscht
|
||||
|
||||
Hinweis: Durch Aktivieren dieser Option wird auch die Videowerbung zwangsweise ausgeblendet."</string>
|
||||
Hinweis: Durch Aktivieren dieser Option wird auch die Videowerbung zwangsweise ausgeblendet"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Erstellungs- und Benachrichtigungs-Buttons tauschen</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Das Deaktivieren kann mehr Werbung vom Server laden.
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Wenn Sie diese Einstellung deaktivieren, wird auch die Anzeigenblockierung für \"Shorts\" deaktiviert.
|
||||
|
||||
Auch Werbung wird nicht mehr in Shorts blockiert.
|
||||
|
||||
Wenn diese Einstellung nicht wirksam ist, versuchen Sie in den Inkognito-Modus zu wechseln."</string>
|
||||
Wenn diese Änderung nicht wirksam wird, versuchen Sie, in den Inkognito-Modus zu wechseln."</string>
|
||||
<string name="revanced_theme_default">Stock</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Warnung</string>
|
||||
|
|
|
|||
|
|
@ -561,9 +561,9 @@
|
|||
<string name="revanced_hide_ask_button_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_ask_button_summary_on">Κρυμμένο.</string>
|
||||
<string name="revanced_hide_ask_button_title">Κουμπί «Ερώτηση»</string>
|
||||
<string name="revanced_hide_ask_section_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_hide_ask_section_summary_on">Κρυμμένη</string>
|
||||
<string name="revanced_hide_ask_section_title">Ενότητα «Ερώτηση»</string>
|
||||
<string name="revanced_hide_ask_section_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_ask_section_summary_on">Κρυμμένη.</string>
|
||||
<string name="revanced_hide_ask_section_title">Ενότητα ερώτησης</string>
|
||||
<string name="revanced_hide_attributes_section_summary_off">Εμφανίζεται.\n\nΑφορά τις ιδιότητες: Επιλεγμένα μέρη, Παιχνίδια, Μουσική, και «Οι χρήστες ανέφεραν».</string>
|
||||
<string name="revanced_hide_attributes_section_summary_on">Κρυμμένη.\n\nΑφορά τις ιδιότητες: Επιλεγμένα μέρη, Παιχνίδια, Μουσική, και «Οι χρήστες ανέφεραν».</string>
|
||||
<string name="revanced_hide_attributes_section_title">Ενότητα ιδιοτήτων</string>
|
||||
|
|
@ -674,6 +674,9 @@ Playlists
|
|||
<string name="revanced_hide_community_posts_subscriptions_summary_off">Εμφανίζονται.</string>
|
||||
<string name="revanced_hide_community_posts_subscriptions_summary_on">Κρυμμένες.</string>
|
||||
<string name="revanced_hide_community_posts_subscriptions_title">Δημοσιεύσεις κοινότητας στη ροή «Εγγραφές»</string>
|
||||
<string name="revanced_hide_creator_section_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_creator_section_summary_on">Κρυμμένη.</string>
|
||||
<string name="revanced_hide_creator_section_title">Ενότητα δημιουργού</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_off">Εμφανίζεται\n\nΑφορά την ενότητα καταστήματος δημιουργού κάτω από την οθόνη αναπαραγωγής.</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_on">Κρυμμένη\n\nΑφορά την ενότητα καταστήματος δημιουργού κάτω από την οθόνη αναπαραγωγής.</string>
|
||||
<string name="revanced_hide_creator_store_shelf_title">Ενότητα καταστήματος δημιουργού</string>
|
||||
|
|
@ -704,9 +707,12 @@ Playlists
|
|||
<string name="revanced_hide_expandable_shelf_summary_off">Εμφανίζονται.</string>
|
||||
<string name="revanced_hide_expandable_shelf_summary_on">Κρυμμένες.</string>
|
||||
<string name="revanced_hide_expandable_shelf_title">Επεκτάσιμες ενότητες</string>
|
||||
<string name="revanced_hide_featured_section_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_hide_featured_section_summary_on">Κρυμμένη</string>
|
||||
<string name="revanced_hide_featured_section_title">Ενότητα προτεινόμενων συνδέσμων</string>
|
||||
<string name="revanced_hide_explore_podcast_section_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_explore_podcast_section_summary_on">Κρυμμένη.</string>
|
||||
<string name="revanced_hide_explore_podcast_section_title">Ενότητα «Εξερευνήστε το podcast»</string>
|
||||
<string name="revanced_hide_featured_section_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_featured_section_summary_on">Κρυμμένη.</string>
|
||||
<string name="revanced_hide_featured_section_title">Ενότητα προτεινόμενου περιεχομένου</string>
|
||||
<string name="revanced_hide_feed_captions_button_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_feed_captions_button_on">Κρυμμένο.</string>
|
||||
<string name="revanced_hide_feed_captions_button_title">Κουμπί υπότιτλων</string>
|
||||
|
|
@ -742,9 +748,9 @@ Playlists
|
|||
<string name="revanced_hide_handle_summary_off">Εμφανίζονται.</string>
|
||||
<string name="revanced_hide_handle_summary_on">Κρυμμένα.</string>
|
||||
<string name="revanced_hide_handle_title">Ψευδώνυμο & διεύθυνση e-mail</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Κρυμμένη</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Ενότητα «Πως δημιουργήθηκε αυτό το περιεχόμενο»</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Κρυμμένη.</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Ενότητα «Πως δημιουργήθηκε»</string>
|
||||
<string name="revanced_hide_hype_button_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_hype_button_summary_on">Κρυμμένο.</string>
|
||||
<string name="revanced_hide_hype_button_title">Κουμπί «Hype»</string>
|
||||
|
|
@ -1297,6 +1303,9 @@ Playlists
|
|||
<string name="revanced_hide_stop_ads_button_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_stop_ads_button_summary_on">Κρυμμένο.</string>
|
||||
<string name="revanced_hide_stop_ads_button_title">Κουμπί «Διακοπή διαφημίσεων»</string>
|
||||
<string name="revanced_hide_subscribe_button_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_subscribe_button_summary_on">Κρυμμένο.</string>
|
||||
<string name="revanced_hide_subscribe_button_title">Κουμπί «Εγγραφή»</string>
|
||||
<string name="revanced_hide_subscribed_channels_bar_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_subscribed_channels_bar_summary_on">Κρυμμένη.</string>
|
||||
<string name="revanced_hide_subscribed_channels_bar_title">Γραμμή εγγεγραμμένων καναλιών</string>
|
||||
|
|
@ -1327,6 +1336,11 @@ Playlists
|
|||
<string name="revanced_hide_toolbar_notification_button_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_summary_on">Κρυμμένο.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_title">Κουμπί ειδοποιήσεων</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_on">"Κρυμμένο.
|
||||
|
||||
Αυτή η ρύθμιση ενδέχεται να μη λειτουργεί αν η ρύθμιση «Ευρεία γραμμή αναζήτησης» είναι ενεργοποιημένη."</string>
|
||||
<string name="revanced_hide_toolbar_search_button_title">Απόκρυψη κουμπιού αναζήτησης</string>
|
||||
<string name="revanced_hide_transcript_section_summary_off">Εμφανίζεται.</string>
|
||||
<string name="revanced_hide_transcript_section_summary_on">Κρυμμένη.</string>
|
||||
<string name="revanced_hide_transcript_section_title">Ενότητα «Μεταγραφή»</string>
|
||||
|
|
@ -1847,6 +1861,13 @@ Playlists
|
|||
<string name="revanced_replace_channel_handle_summary_off">Εμφανίζεται το ψευδώνυμο καναλιού.</string>
|
||||
<string name="revanced_replace_channel_handle_summary_on">Εμφανίζεται το όνομα καναλιού.</string>
|
||||
<string name="revanced_replace_channel_handle_title">Αντικατάσταση ονόματος καναλιού</string>
|
||||
<string name="revanced_replace_navigation_button_summary">Αντικατάσταση του κουμπιού πλοήγησης με το κουμπί αναζήτησης.</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_home">Αρχική</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_notifications">Ειδοποιήσεις</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_shorts">Shorts</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_subscriptions">Εγγραφές</string>
|
||||
<string name="revanced_replace_navigation_button_target_title">Αντικατάσταση κουμπιού πλοήγησης</string>
|
||||
<string name="revanced_replace_navigation_button_title">Αντικατάσταση κουμπιού πλοήγησης</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_off">Πατήστε για να δείτε τον χρόνο που απομένει.</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_on">Πατήστε για να ανοίξετε το μενού ταχύτητας αναπαραγωγής ή ποιότητας βίντεο.</string>
|
||||
<string name="revanced_replace_time_stamp_action_title">Αντικατάσταση ενέργειας χρονοσφραγίδας</string>
|
||||
|
|
@ -2271,6 +2292,7 @@ Playlists
|
|||
<string name="revanced_spoof_app_version_target_entry_19_28_42">19.28.42 - Επαναφορά παλιάς επικεφαλίδας λίστας αναπαραγωγής</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_19_33_37">19.33.37 - Επαναφορά αναδυόμενου πίνακα ταχύτητας αναπαραγωγής παλιού στυλ</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_05_46">20.05.46 - Επαναφορά λειτουργικότητας μεταγραφής</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_13_41">20.13.41 - Επαναφορά μη καταρρέουσας γραμμής ενέργειας βίντεο</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_title">Έκδοση παραποίησης της εφαρμογής</string>
|
||||
<string name="revanced_spoof_app_version_target_invalid_toast">Μη έγκυρη έκδοση για παραποίηση: %s.</string>
|
||||
<string name="revanced_spoof_app_version_target_summary">Πληκτρολογήστε την έκδοση εφαρμογής που θα εφαρμοστεί.</string>
|
||||
|
|
@ -2589,15 +2611,9 @@ Playlists
|
|||
• Όταν ενεργοποιηθεί, μπορεί να μη λειτουργήσει μέχρι να γίνει επανεκκίνηση της συσκευής σας.
|
||||
• Η ενεργοποίηση αυτής της ρύθμισης εξαναγκάζει επίσης την απενεργοποίηση των διαφημίσεων βίντεο."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Δεν γίνεται εναλλαγή θέσεων των κουμπιών «Δημιουργία» και «Ειδοποιήσεις».</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Γίνεται εναλλαγή θέσεων των κουμπιών «Δημιουργία» και «Ειδοποιήσεις».
|
||||
|
||||
Σημείωση: Η ενεργοποίηση αυτής της ρύθμισης εξαναγκάζει επίσης την απόκρυψη των διαφημίσεων βίντεο."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">Γίνεται εναλλαγή θέσεων του κουμπιού δημιουργίας με του κουμπιού ειδοποιήσεων.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Εναλλαγή «Δημιουργία» με «Ειδοποιήσεις»</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Η απενεργοποίηση αυτής της ρύθμισης μπορεί να έχει ως αποτέλεσμα την φόρτωση περισσότερων διαφημίσεων από τον διακομιστή.
|
||||
|
||||
Επίσης, ενδέχεται να εμφανίζονται διαφημίσεις στα Shorts.
|
||||
|
||||
Αν η απενεργοποίηση δεν τεθεί σε ισχύ, δοκιμάστε να μεταβείτε σε λειτουργία ανώνυμης περιήγησης."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">Αν αυτή η ρύθμιση δεν τεθεί σε ισχύ, δοκιμάστε να ενεργοποιήσετε τη λειτουργία ανώνυμης περιήγησης.</string>
|
||||
<string name="revanced_theme_default">Προεπιλογή</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Προειδοποίηση</string>
|
||||
|
|
|
|||
|
|
@ -700,9 +700,9 @@ Tienda"</string>
|
|||
<string name="revanced_hide_community_posts_subscriptions_summary_off">Visible en el feed de suscripciones.</string>
|
||||
<string name="revanced_hide_community_posts_subscriptions_summary_on">Oculto en el feed de suscripciones.</string>
|
||||
<string name="revanced_hide_community_posts_subscriptions_title">Ocultar en feed de suscripciones</string>
|
||||
<string name="revanced_hide_creator_section_summary_off">La sección «Creador» está visible.</string>
|
||||
<string name="revanced_hide_creator_section_summary_on">La sección «Creador» está oculta.</string>
|
||||
<string name="revanced_hide_creator_section_title">Ocultar sección «Creador»</string>
|
||||
<string name="revanced_hide_creator_section_summary_off">La sección de creador está visible.</string>
|
||||
<string name="revanced_hide_creator_section_summary_on">La sección de creador está oculta.</string>
|
||||
<string name="revanced_hide_creator_section_title">Ocultar sección de creador</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_off">El estante de la tienda del creador debajo de los vídeos está visible.</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_on">El estante de la tienda del creador debajo de los vídeos está oculta.</string>
|
||||
<string name="revanced_hide_creator_store_shelf_title">Ocultar estante de la tienda del creador</string>
|
||||
|
|
@ -736,8 +736,8 @@ Configuración → Reproducción → Reproducción automática del siguiente ví
|
|||
<string name="revanced_hide_explore_podcast_section_summary_off">La sección «Explorar el podcast» está visible.</string>
|
||||
<string name="revanced_hide_explore_podcast_section_summary_on">La sección «Explorar el podcast» está oculta.</string>
|
||||
<string name="revanced_hide_explore_podcast_section_title">Ocultar sección «Explorar el podcast»</string>
|
||||
<string name="revanced_hide_featured_section_summary_off">La sección «Contenido destacado» en la sección «Creador» está visible.</string>
|
||||
<string name="revanced_hide_featured_section_summary_on">La sección «Contenido destacado» en la sección «Creador» está oculta.</string>
|
||||
<string name="revanced_hide_featured_section_summary_off">La sección de contenido destacado en la sección de creador está visible.</string>
|
||||
<string name="revanced_hide_featured_section_summary_on">La sección de contenido destacado en la sección de creador está oculta.</string>
|
||||
<string name="revanced_hide_featured_section_title">Ocultar sección «Contenido destacado»</string>
|
||||
<string name="revanced_hide_feed_captions_button_off">El botón de subtítulos está visible.</string>
|
||||
<string name="revanced_hide_feed_captions_button_on">El botón de subtítulos está oculto.</string>
|
||||
|
|
@ -1298,8 +1298,8 @@ Limitación: las cabeceras oficiales en los resultados de búsqueda estarán ocu
|
|||
<string name="revanced_hide_stop_ads_button_summary_off">El botón para detener los anuncios está visible.</string>
|
||||
<string name="revanced_hide_stop_ads_button_summary_on">El botón para detener los anuncios está oculto.</string>
|
||||
<string name="revanced_hide_stop_ads_button_title">Ocultar Detener anuncios</string>
|
||||
<string name="revanced_hide_subscribe_button_summary_off">El botón «Suscribirme» en la sección «Creador» está visible.</string>
|
||||
<string name="revanced_hide_subscribe_button_summary_on">El botón «Suscribirme» en la sección «Creador» está oculto.</string>
|
||||
<string name="revanced_hide_subscribe_button_summary_off">El botón «Suscribirme» en la sección de creador está visible.</string>
|
||||
<string name="revanced_hide_subscribe_button_summary_on">El botón «Suscribirme» en la sección de creador está oculto.</string>
|
||||
<string name="revanced_hide_subscribe_button_title">Ocultar botón «Suscribirme»</string>
|
||||
<string name="revanced_hide_subscribed_channels_bar_summary_off">La barra de canales suscritos está visible.</string>
|
||||
<string name="revanced_hide_subscribed_channels_bar_summary_on">La barra de canales suscritos está oculta.</string>
|
||||
|
|
@ -1331,6 +1331,11 @@ Limitación: las cabeceras oficiales en los resultados de búsqueda estarán ocu
|
|||
<string name="revanced_hide_toolbar_notification_button_summary_off">El botón de notificaciones está visible.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_summary_on">El botón de notificaciones está oculto.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_title">Ocultar botón de notificaciones</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_off">El botón de buscar está visible.</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_on">"El botón de buscar está oculto.
|
||||
|
||||
Este ajuste puede no funcionar si la barra de búsqueda ancha está activada."</string>
|
||||
<string name="revanced_hide_toolbar_search_button_title">Ocultar botón de buscar</string>
|
||||
<string name="revanced_hide_transcript_section_summary_off">Las secciones de transcripción están visibles.</string>
|
||||
<string name="revanced_hide_transcript_section_summary_on">Las secciones de transcripción están ocultas.</string>
|
||||
<string name="revanced_hide_transcript_section_title">Ocultar secciones de transcripción</string>
|
||||
|
|
@ -1850,6 +1855,13 @@ Esto no evita la restricción de edad. Solo la acepta automáticamente."</string
|
|||
<string name="revanced_replace_channel_handle_summary_off">Se utiliza el nombre de usuario del canal.</string>
|
||||
<string name="revanced_replace_channel_handle_summary_on">Se utiliza el nombre del canal.</string>
|
||||
<string name="revanced_replace_channel_handle_title">Reemplazar nombre de usuario del canal</string>
|
||||
<string name="revanced_replace_navigation_button_summary">Reemplaza el botón de navegación con el botón de búsqueda.</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_home">Inicio</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_notifications">Notificaciones</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_shorts">Shorts</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_subscriptions">Suscripciones</string>
|
||||
<string name="revanced_replace_navigation_button_target_title">Reemplazar botón de navegación</string>
|
||||
<string name="revanced_replace_navigation_button_title">Reemplazar botón de navegación</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_off">Pulsa para mostrar el tiempo restante.</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_on">Pulsa para abrir el menú desplegable de velocidad de reproducción o de calidad de vídeo.</string>
|
||||
<string name="revanced_replace_time_stamp_action_title">Reemplazar acción de marca de tiempo</string>
|
||||
|
|
@ -2268,6 +2280,7 @@ Limitación: el título de vídeo desaparece cuando se pulsa."</string>
|
|||
<string name="revanced_spoof_app_version_target_entry_19_28_42">19.28.42 - Restaura el antiguo encabezado de la lista de reproducción</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_19_33_37">19.33.37 - Restaurar el antiguo panel desplegable de velocidad de reproducción</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_05_46">20.05.46 - Restaurar funcionalidad de transcripción</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_13_41">20.13.41 - Restaurar la barra de acción de vídeo no contraída</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_title">Versión a falsificar de la app</string>
|
||||
<string name="revanced_spoof_app_version_target_invalid_toast">Versión de aplicación falsa no válida: %s.</string>
|
||||
<string name="revanced_spoof_app_version_target_summary">Escribe la versión a falsificar de la app.</string>
|
||||
|
|
@ -2581,15 +2594,9 @@ Ajusta el volumen deslizando verticalmente en el lado derecho de la pantalla."</
|
|||
• Al desactivar este ajuste se cargan más anuncios desde el servidor.
|
||||
• Debes desactivar este ajuste para que los anuncios de vídeo sean visibles."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">El botón de crear no se cambia por el botón de notificaciones.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"El botón de crear se cambia por el botón de notificaciones.
|
||||
|
||||
Nota: Al activar esto también se ocultan forzosamente los anuncios de vídeos."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">El botón de crear se cambia por el botón de notificaciones.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Cambiar botón de crear con el de notificaciones</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Desactivar esto podría cargar más anuncios del servidor.
|
||||
|
||||
Además, los anuncios ya no se bloquearán en Shorts.
|
||||
|
||||
Si este ajuste no surte efecto, prueba a cambiar al modo incógnito."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">Si este ajuste no surte efecto, intente cambiar al modo incógnito.</string>
|
||||
<string name="revanced_theme_default">Predeterminado</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Advertencia</string>
|
||||
|
|
|
|||
|
|
@ -2529,15 +2529,13 @@ Ajustez le volume en balayant verticalement sur le côté droit de l'écran."</s
|
|||
• Désactiver ce paramètre charge plus de publicités depuis le serveur.
|
||||
• Vous devez désactiver ce paramètre afin de rendre les publicités vidéo visibles."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Le bouton \'Créer\' n\'est pas échangé avec le bouton \'Notification\'.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Le bouton 'Créer' est échangé avec le bouton 'Notification'.
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Le bouton Créer est échangé avec le bouton Notifications
|
||||
|
||||
Note : Activer ceci masquera également les publicités vidéos."</string>
|
||||
Remarque : Activer cette option masque également de force les annonces vidéo"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Échanger \'Créer\' et \'Notifications\'</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Désactiver ceci pourrait charger plus de publicités depuis le serveur.
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"La désactivation de ce paramètre désactivera également le blocage des publicités Shorts.
|
||||
|
||||
Également, les publicités ne seront plus bloquées sur les Shorts.
|
||||
|
||||
Si ce paramètre ne fait pas effet, essayer de passer en mode Incognito."</string>
|
||||
Si la modification de ce paramètre ne prend pas effet, essayez de passer en mode navigation privée."</string>
|
||||
<string name="revanced_theme_default">Officiel</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Attention</string>
|
||||
|
|
|
|||
|
|
@ -564,9 +564,9 @@ Információ:
|
|||
<string name="revanced_hide_ask_button_summary_off">A kérdés gomb látható.</string>
|
||||
<string name="revanced_hide_ask_button_summary_on">A kérdés gomb el van rejtve.</string>
|
||||
<string name="revanced_hide_ask_button_title">Kérdés gomb elrejtése</string>
|
||||
<string name="revanced_hide_ask_section_summary_off">A kérdezés szakasz megjelenik</string>
|
||||
<string name="revanced_hide_ask_section_summary_on">A kérdezés szakasz el van rejtve</string>
|
||||
<string name="revanced_hide_ask_section_title">Kérdezés elrejtése</string>
|
||||
<string name="revanced_hide_ask_section_summary_off">A kérdés rész látható.</string>
|
||||
<string name="revanced_hide_ask_section_summary_on">A kérdés rész rejtett.</string>
|
||||
<string name="revanced_hide_ask_section_title">Kérdés rész elrejtése</string>
|
||||
<string name="revanced_hide_attributes_section_summary_off">A kiemelt helyek, a Játékok és a Zene szakaszok láthatóak.</string>
|
||||
<string name="revanced_hide_attributes_section_summary_on">A kiemelt helyek, a játékok, a zene és a megemlített emberek részek el vannak rejtve.</string>
|
||||
<string name="revanced_hide_attributes_section_title">Tulajdonságok szakasz elrejtése</string>
|
||||
|
|
@ -674,6 +674,9 @@ Lejátszási listák
|
|||
<string name="revanced_hide_community_posts_subscriptions_summary_off">Látható a feliratkozások között.</string>
|
||||
<string name="revanced_hide_community_posts_subscriptions_summary_on">Elrejtve a feliratkozások között.</string>
|
||||
<string name="revanced_hide_community_posts_subscriptions_title">Elrejtés a feliratkozások között</string>
|
||||
<string name="revanced_hide_creator_section_summary_off">A létrehozói rész látható.</string>
|
||||
<string name="revanced_hide_creator_section_summary_on">A létrehozói rész rejtett.</string>
|
||||
<string name="revanced_hide_creator_section_title">Létrehozói rész elrejtése</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_off">A videók alatti alkotói áruház polc látható.</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_on">A videók alatti alkotói áruház polc el van rejtve.</string>
|
||||
<string name="revanced_hide_creator_store_shelf_title">Alkotói áruház polcának elrejtése</string>
|
||||
|
|
@ -704,9 +707,12 @@ Beállítások → Automatikus lejátszás / Lejátszás → Következő videó
|
|||
<string name="revanced_hide_expandable_shelf_summary_off">A kinyitható polcok láthatóak.</string>
|
||||
<string name="revanced_hide_expandable_shelf_summary_on">A kinyitható polcok el vannak rejtve.</string>
|
||||
<string name="revanced_hide_expandable_shelf_title">Kinyitható polcok elrejtése</string>
|
||||
<string name="revanced_hide_featured_section_summary_off">A kiemelt tartalmak szekció látható</string>
|
||||
<string name="revanced_hide_featured_section_summary_on">A kiemelt tartalmak szekció elrejtve</string>
|
||||
<string name="revanced_hide_featured_section_title">Kiemelt tartalom elrejtése</string>
|
||||
<string name="revanced_hide_explore_podcast_section_summary_off">A podcastok felfedezése rész látható.</string>
|
||||
<string name="revanced_hide_explore_podcast_section_summary_on">A podcastok felfedezése rész rejtett.</string>
|
||||
<string name="revanced_hide_explore_podcast_section_title">Podcastok felfedezése rész elrejtése</string>
|
||||
<string name="revanced_hide_featured_section_summary_off">A Kiemelt tartalom rész látható az Alkotó részben.</string>
|
||||
<string name="revanced_hide_featured_section_summary_on">A Kiemelt tartalom rész rejtett az Alkotó részben.</string>
|
||||
<string name="revanced_hide_featured_section_title">Kiemelt tartalom rész elrejtése</string>
|
||||
<string name="revanced_hide_feed_captions_button_off">A feliratok gomb látható.</string>
|
||||
<string name="revanced_hide_feed_captions_button_on">A feliratok gomb el van rejtve.</string>
|
||||
<string name="revanced_hide_feed_captions_button_title">Feliratok gomb elrejtése</string>
|
||||
|
|
@ -2570,15 +2576,13 @@ A hangerő beállításához simítson függőlegesen a képernyő jobb oldalán
|
|||
• Ha ezt a beállítást letiltja, több hirdetést tölt be a szerver oldalról.
|
||||
• Ha a videó hirdetések láthatóak akarja tenni, letiltja ezt a beállítást."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">A Létrehozás gomb nincs felcserélve az Értesítések gombbal.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"A létrehozás gomb helyet cserél az értesítések gombbal.
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"A Létrehozás gomb kicserélve az Értesítések gombbal
|
||||
|
||||
Megjegyzés: engedélyezés esetén a videó hirdetéseket is elrejti."</string>
|
||||
Megjegyzés: Ez a beállítás a videóhirdetések kényszerű elrejtését is magában foglalja"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Létrehozás és értesítések gombok felcserélése</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Ennek kikapcsolása esetleg több reklámot tölt be a szerverről.
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Ennek a beállításnak a letiltása a Shorts hirdetések blokkolását is letiltja.
|
||||
|
||||
Tovább, a reklámok nem lesznek tiltva a Shortokban.
|
||||
|
||||
Ha ez a beállítás nem működik, váltson inkognító módra."</string>
|
||||
Ha a beállítás módosítása nem lép életbe, próbáljon meg Inkognitó módra váltani."</string>
|
||||
<string name="revanced_theme_default">Alap</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Figyelmeztetés</string>
|
||||
|
|
|
|||
|
|
@ -1093,9 +1093,9 @@ Sesuaikan kecerahan dengan mengusap secara vertikal pada sisi kiri layar"</strin
|
|||
Menyesuaikan volume dengan mengusap secara vertikal di sisi kanan layar"</string>
|
||||
<string name="revanced_swipe_volume_title">Aktifkan gerakan volume</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Tombol Buat tidak bertukar posisi dengan tombol Pemberitahuan.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Tombol Buat ditukar dengan tombol Notifikasi.
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Tombol buat diganti dengan tombol Notifikasi
|
||||
|
||||
Catatan: Mengaktifkan ini juga secara paksa menyembunyikan iklan video."</string>
|
||||
Catatan: Mengaktifkan ini juga akan memaksa menyembunyikan iklan video"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Tukar tombol buat dan pemberitahuan</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Menonaktifkan setelan ini juga akan menonaktifkan pemblokiran iklan di Shorts.
|
||||
|
||||
|
|
|
|||
|
|
@ -1354,6 +1354,11 @@ Nota: lo scaffale Cronologia nella scheda Tu potrebbe essere nascosto."</string>
|
|||
<string name="revanced_hide_toolbar_notification_button_summary_off">Il pulsante Notifiche è visibile.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_summary_on">Il pulsante Notifiche è nascosto.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_title">Nascondi il pulsante Notifiche</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_off">Il pulsante Cerca è visibile.</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_on">"Il pulsante Cerca è nascosto.
|
||||
|
||||
Nota: questa impostazione potrebbe non funzionare se la barra di ricerca estesa è attivata."</string>
|
||||
<string name="revanced_hide_toolbar_search_button_title">Nascondi il pulsante Cerca</string>
|
||||
<string name="revanced_hide_transcript_section_summary_off">La sezione Trascrizione è visibile.</string>
|
||||
<string name="revanced_hide_transcript_section_summary_on">La sezione Trascrizione è nascosta.</string>
|
||||
<string name="revanced_hide_transcript_section_title">Nascondi la sezione Trascrizione</string>
|
||||
|
|
@ -1902,6 +1907,13 @@ Nota: questo non bypassa la restrizione di età, ma la accetta automaticamente."
|
|||
<string name="revanced_replace_channel_handle_summary_off">L\'handle è visibile.</string>
|
||||
<string name="revanced_replace_channel_handle_summary_on">Il nome del canale è visibile.</string>
|
||||
<string name="revanced_replace_channel_handle_title">Sostituisci l\'handle con il nome del canale</string>
|
||||
<string name="revanced_replace_navigation_button_summary">Sostituisce il pulsante Navigazione con il pulsante Cerca.</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_home">Home</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_notifications">Notifiche</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_shorts">Shorts</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_subscriptions">Iscrizioni</string>
|
||||
<string name="revanced_replace_navigation_button_target_title">Cambia la destinazione del pulsante Navigazione</string>
|
||||
<string name="revanced_replace_navigation_button_title">Sostituisci il pulsante Navigazione con il pulsante Cerca</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_off">Tocca per mostrare il tempo rimanente.</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_on">Tocca per aprire la finestra della velocità di riproduzione o della qualità video.</string>
|
||||
<string name="revanced_replace_time_stamp_action_title">Sostituisci l\'azione del timestamp</string>
|
||||
|
|
@ -2342,6 +2354,7 @@ Note:
|
|||
<string name="revanced_spoof_app_version_target_entry_19_28_42">19.28.42 - Ripristina la vecchia intestazione delle playlist</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_19_33_37">19.33.37 - Ripristina il vecchio pannello della velocità di riproduzione</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_05_46">20.05.46 - Ripristina la trascrizione</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_13_41">20.13.41 - Ripristina la barra delle azioni non compressa dei video</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_title">Versione dell\'app da camuffare</string>
|
||||
<string name="revanced_spoof_app_version_target_invalid_toast">Versione dell\'app da camuffare non valida: %s</string>
|
||||
<string name="revanced_spoof_app_version_target_summary">Digita la versione dell\'app da camuffare.</string>
|
||||
|
|
@ -2660,15 +2673,9 @@ Regola il volume scorrendo verticalmente sul lato destro dello schermo."</string
|
|||
• Disabilitare questa impostazione carica più annunci dal lato server.
|
||||
• Dovresti disabilitare questa impostazione per rendere visibili gli annunci nei video."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Il pulsante Crea non è sostituito dal pulsante Notifiche.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Il pulsante Crea è sostituito dal pulsante Notifiche.
|
||||
|
||||
Nota: anche gli annunci video saranno nascosti."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">Il pulsante Crea è sostituito dal pulsante Notifiche.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Sostituisci il pulsante Crea con il pulsante Notifiche</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"La disattivazione di questa impostazione potrebbe caricare più annunci dal server.
|
||||
|
||||
Inoltre, gli annunci degli Shorts non saranno più bloccati.
|
||||
|
||||
Se questa impostazione non ha effetto, prova a passare alla navigazione in incognito."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">Se questa impostazione non ha effetto, prova a passare a in incognito.</string>
|
||||
<string name="revanced_theme_default">Predefinito</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Attenzione</string>
|
||||
|
|
|
|||
|
|
@ -749,6 +749,9 @@ DeArrow について詳しく知るには、ここをタップしてください
|
|||
<string name="revanced_hide_expandable_shelf_summary_off">検索結果にある、展開可能な棚を非表示にします。</string>
|
||||
<string name="revanced_hide_expandable_shelf_summary_on">検索結果にある、展開可能な棚を非表示にします。</string>
|
||||
<string name="revanced_hide_expandable_shelf_title">展開可能な棚を非表示</string>
|
||||
<string name="revanced_hide_explore_podcast_section_summary_off">概要欄から「ポッドキャストを検索」欄を非表示にします。</string>
|
||||
<string name="revanced_hide_explore_podcast_section_summary_on">概要欄から「ポッドキャストを検索」欄を非表示にします。</string>
|
||||
<string name="revanced_hide_explore_podcast_section_title">「ポッドキャストを検索」欄を非表示</string>
|
||||
<string name="revanced_hide_featured_section_summary_off">クリエイター欄内から注目の動画を非表示にします。</string>
|
||||
<string name="revanced_hide_featured_section_summary_on">クリエイター欄内から注目の動画を非表示にします。</string>
|
||||
<string name="revanced_hide_featured_section_title">注目のコンテンツ欄を非表示</string>
|
||||
|
|
@ -2711,15 +2714,13 @@ JavaScript クライアントの中では、「TV」が推奨されます。"</s
|
|||
• この設定を無効にすると、サーバーからさらに多くの広告が読み込まれます。
|
||||
• 動画広告を表示するには、この設定を無効にする必要があります。"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">[作成] ボタンと [通知] ボタンを入れ替えます。\n\n注意: これを有効にすると、動画広告が強制的に非表示になります。</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"[作成] ボタンと [通知] ボタンを入れ替えます。
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"作成ボタンと通知ボタンが入れ替わります
|
||||
|
||||
注意: これを有効にすると、動画広告が強制的に非表示になります。"</string>
|
||||
注: これにより、動画広告も強制的に非表示になります"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">[作成] ボタンと [通知] ボタンを入れ替え</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"これを無効にすると、サーバーからさらに多くの広告が読み込まれる可能性があります。
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"この設定を無効にすると、ショート動画の広告ブロックも無効になります。
|
||||
|
||||
また、ショートで広告がブロックされなくなります。
|
||||
|
||||
この設定が有効にならない場合は、シークレットモードに切り替えてみてください。"</string>
|
||||
この設定を変更しても効果がない場合は、シークレット モードに切り替えてみてください。"</string>
|
||||
<string name="revanced_theme_default">オリジナル</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">注意</string>
|
||||
|
|
|
|||
|
|
@ -1387,6 +1387,11 @@ MainThread에서 무언가를 테스트할 경우에 사용할 수 있습니다.
|
|||
<string name="revanced_hide_toolbar_notification_button_summary_off">알림 버튼이 표시됩니다.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_summary_on">알림 버튼이 숨겨집니다.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_title">알림 버튼 숨기기</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_off">검색 버튼이 표시됩니다.</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_on">"검색 버튼이 숨겨집니다.
|
||||
|
||||
넓은 검색창이 활성화되어있는 경우에는 이 설정이 작동하지 않을 수 있습니다."</string>
|
||||
<string name="revanced_hide_toolbar_search_button_title">검색 버튼 숨기기</string>
|
||||
<string name="revanced_hide_transcript_section_summary_off">스크립트 섹션이 표시됩니다.</string>
|
||||
<string name="revanced_hide_transcript_section_summary_on">스크립트 섹션이 숨겨집니다.</string>
|
||||
<string name="revanced_hide_transcript_section_title">스크립트 섹션 숨기기</string>
|
||||
|
|
@ -1933,6 +1938,13 @@ Gemini API Key를 발급받으려면 여기를 누르세요."</string>
|
|||
<string name="revanced_replace_channel_handle_summary_off">채널 핸들(@채널 아이디)을 사용합니다.</string>
|
||||
<string name="revanced_replace_channel_handle_summary_on">채널 이름을 사용합니다.</string>
|
||||
<string name="revanced_replace_channel_handle_title">채널 핸들 변경하기</string>
|
||||
<string name="revanced_replace_navigation_button_summary">탐색 버튼을 검색 버튼으로 변경합니다.</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_home">홈</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_notifications">알림</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_shorts">Shorts</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_subscriptions">구독</string>
|
||||
<string name="revanced_replace_navigation_button_target_title">탐색 버튼 변경하기</string>
|
||||
<string name="revanced_replace_navigation_button_title">탐색 버튼 변경하기</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_off">타임스탬프를 탭하면 남은 시간을 표시할 수 있습니다.</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_on">타임스탬프를 탭하면 동영상 재생 속도 또는 동영상 화질 설정 메뉴 구성요소를 열 수 있습니다.</string>
|
||||
<string name="revanced_replace_time_stamp_action_title">타임스탬프 탭하기 동작 변경하기</string>
|
||||
|
|
@ -2382,6 +2394,7 @@ Cookies를 사용한다고 해서 문제가 해결되는 것은 아닙니다.
|
|||
<string name="revanced_spoof_app_version_target_entry_19_28_42">19.28.42 - 이전 재생목록 헤더로 복원합니다.</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_19_33_37">19.33.37 - 이전 동영상 재생 속도 구성요소 패널을 복원합니다.</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_05_46">20.05.46 - 스크립트 기능을 복원합니다.</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_13_41">20.13.41 - 접히지 않은 동영상 동작바를 복원합니다.</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_title">변경할 앱 버전</string>
|
||||
<string name="revanced_spoof_app_version_target_invalid_toast">변경할 앱 버전이 잘못되었습니다: %s</string>
|
||||
<string name="revanced_spoof_app_version_target_summary">변경할 앱 버전을 입력하세요.</string>
|
||||
|
|
@ -2720,15 +2733,9 @@ JavaScript 클라이언트 중에서 권장되는 클라이언트는 TV입니다
|
|||
• 이 설정을 활성화하면 일부 광고가 강제로 숨겨집니다. (동영상 광고, 일반 레이아웃 광고)
|
||||
• 광고 설정에 있는 일부 설정들을 비활성화하려면 이 설정도 비활성화해야 합니다."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">만들기 버튼과 알림 버튼의 위치를 교환하지 않습니다.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"만들기 버튼과 알림 버튼의 위치를 교환합니다.
|
||||
|
||||
알림: 이 설정을 활성화하면 동영상 광고도 강제로 숨겨집니다."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">만들기 버튼과 알림 버튼의 위치를 교환합니다.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">만들기 버튼과 알림 버튼 위치 교환하기</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"이 설정을 비활성화하면 서버에서 더 많은 광고가 불러오게 될 수 있습니다.
|
||||
|
||||
또한, Shorts에서 광고가 더 이상 숨겨지지 않습니다.
|
||||
|
||||
이 설정이 적용되지 않는 경우에는 시크릿 모드로 전환해 보세요."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">이 설정이 적용되지 않는 경우에는 시크릿 모드로 전환해 보세요.</string>
|
||||
<string name="revanced_theme_default">YouTube</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">경고</string>
|
||||
|
|
|
|||
|
|
@ -1372,6 +1372,11 @@ Efekt uboczny: półka z historią oglądania w zakładce Ty może być ukryta."
|
|||
<string name="revanced_hide_toolbar_notification_button_summary_off">Widoczny</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_summary_on">Ukryty</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_title">Przycisk do powiadomień</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_off">Widoczny</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_on">"Ukryty
|
||||
|
||||
Opcja może nie działać, gdy włączony jest szeroki pasek wyszukiwania."</string>
|
||||
<string name="revanced_hide_toolbar_search_button_title">Przycisk od wyszukiwania</string>
|
||||
<string name="revanced_hide_transcript_section_summary_off">Widoczne</string>
|
||||
<string name="revanced_hide_transcript_section_summary_on">Ukryte</string>
|
||||
<string name="revanced_hide_transcript_section_title">Transkrypcje</string>
|
||||
|
|
@ -1921,6 +1926,13 @@ Nie pomija to ograniczeń wiekowych, lecz akceptuje je automatycznie."</string>
|
|||
<string name="revanced_replace_channel_handle_summary_off">Po nicku</string>
|
||||
<string name="revanced_replace_channel_handle_summary_on">Po nazwie</string>
|
||||
<string name="revanced_replace_channel_handle_title">Wyświetlanie tytułu kanału</string>
|
||||
<string name="revanced_replace_navigation_button_summary">Zastępuje przycisk nawigacyjny przyciskiem od wyszukiwania.</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_home">Strona główna</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_notifications">Powiadomienia</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_shorts">Shortsy</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_subscriptions">Subskrypcje</string>
|
||||
<string name="revanced_replace_navigation_button_target_title">Wybierz przycisk do zastąpienia</string>
|
||||
<string name="revanced_replace_navigation_button_title">Zastąp przycisk nawigacji</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_off">Stuknij, aby wyświetlić pozostały czas.</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_on">Stuknij, aby otworzyć menu od prędkości odtwarzania lub jakości.</string>
|
||||
<string name="revanced_replace_time_stamp_action_title">Działanie informacji obok czasu</string>
|
||||
|
|
@ -2367,6 +2379,7 @@ Ograniczenie: tytuły filmów znikają po stuknięciu w nie."</string>
|
|||
<string name="revanced_spoof_app_version_target_entry_19_28_42">19.28.42 - Przywraca stary nagłówek playlist</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_19_33_37">19.33.37 - Przywraca stare menu szybkości odtwarzania</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_05_46">20.05.46 - Przywraca funkcjonalność transkrypcji</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_13_41">20.13.41 - Przywraca nieskondensowany pasek akcji filmu</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_title">Oszukiwana wersja aplikacji</string>
|
||||
<string name="revanced_spoof_app_version_target_invalid_toast">Nieprawidłowa oszukiwana wersja aplikacji: %s.</string>
|
||||
<string name="revanced_spoof_app_version_target_summary">Wpisz wersję, którą chcesz oszukiwać</string>
|
||||
|
|
@ -2716,15 +2729,9 @@ Dostosuj głośność, przesuwając pionowo po prawej stronie ekranu."</string>
|
|||
• Wyłączenie tego ustawienia powoduje zwiększenie ilości reklam.
|
||||
• Powinieneś wyłączyć to ustawienie jeśli chcesz, by reklamy w filmach były widoczne."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Nie zamienone</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Zamienione
|
||||
|
||||
Notka: włączenie tej opcji wymusza ukrywanie reklam w filmach."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">Zamienione</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Zamień przyciski przesyłania i powiadomień</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Wyłączenie tej opcji może spowodować załadowanie się większej ilości reklam z serwera.
|
||||
|
||||
Dodatkowo, reklamy nie będą już blokowane w Shortsach.
|
||||
|
||||
Jeśli opcja nie przynosi skutku, spróbuj przełączyć się na tryb incognito."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">Jeśli opcja nie poskutkuje, spróbuj przełączyć się w tryb incognito.</string>
|
||||
<string name="revanced_theme_default">Domyślny</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Ostrzeżenie</string>
|
||||
|
|
|
|||
|
|
@ -2544,15 +2544,13 @@ Ajuste o volume deslizando verticalmente no lado direito da tela."</string>
|
|||
• Desativar esta configuração carrega mais anúncios do lado do servidor.
|
||||
• Você deve desativar esta configuração para tornar os anúncios em vídeo visíveis."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">O botão criar não está alternado com o botão Notificações.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"O botão criar é alternado com o botão notificações.
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"O botão Criar é trocado com o botão Notificações
|
||||
|
||||
Nota: Ativar isso também oculta anúncios de vídeo à força."</string>
|
||||
Nota: Habilitar isso também oculta os anúncios em vídeo"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Alternar criar com notificações</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Desativar isso pode carregar mais anúncios do servidor.
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Desativar esta configuração também desativará o bloqueio de anúncios do Shorts.
|
||||
|
||||
Além disso, os anúncios não serão mais bloqueados no Shorts.
|
||||
|
||||
Se essa configuração não surtir efeito, tente alternar para o modo anônimo."</string>
|
||||
Se alterar esta configuração não fizer efeito, tente mudar para o modo anônimo."</string>
|
||||
<string name="revanced_theme_default">Padrão</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Aviso</string>
|
||||
|
|
|
|||
|
|
@ -171,10 +171,10 @@
|
|||
<string name="revanced_custom_filter_summary_on">Пользовательский фильтр включен.</string>
|
||||
<string name="revanced_custom_filter_title">Пользовательский фильтр</string>
|
||||
<string name="revanced_custom_filter_toast_invalid_syntax">Недопустимый фильтр: %s.</string>
|
||||
<string name="revanced_custom_playback_speed_menu_type_entry_custom_legacy">Свой (Предыдущий)</string>
|
||||
<string name="revanced_custom_playback_speed_menu_type_entry_custom_legacy">Свой (Старый)</string>
|
||||
<string name="revanced_custom_playback_speed_menu_type_entry_custom_modern">Свой (Современный)</string>
|
||||
<string name="revanced_custom_playback_speed_menu_type_entry_custom_no_theme">Свой (Без темы)</string>
|
||||
<string name="revanced_custom_playback_speed_menu_type_entry_youtube_legacy">YouTube Предыдущий</string>
|
||||
<string name="revanced_custom_playback_speed_menu_type_entry_youtube_legacy">YouTube Старый</string>
|
||||
<string name="revanced_custom_playback_speed_menu_type_summary_off">Современный стиль всплывающего меню скорости воспроизведения.</string>
|
||||
<string name="revanced_custom_playback_speed_menu_type_summary_on">Пользовательское меню скорости воспроизведения.</string>
|
||||
<string name="revanced_custom_playback_speed_menu_type_title">Стиль меню скорости</string>
|
||||
|
|
@ -234,11 +234,11 @@
|
|||
<string name="revanced_disable_auto_audio_tracks_not_available">Чтобы использовать эту функцию, измените \'Клиент по умолчанию (Подмена потоковых данных)\' на TV, TV Simply или iOS TV.</string>
|
||||
<string name="revanced_disable_auto_audio_tracks_summary_off">"Принудительные автоматические звуковые дорожки включены."</string>
|
||||
<string name="revanced_disable_auto_audio_tracks_summary_on">Принудительные автоматические звуковые дорожки отключены.</string>
|
||||
<string name="revanced_disable_auto_audio_tracks_summary_on_disclaimer">"Принудительные аудио авто дорожки отключены.
|
||||
<string name="revanced_disable_auto_audio_tracks_summary_on_disclaimer">"Принудительное автоматическое воспроизведение звуковых дорожек отключено.
|
||||
|
||||
Вероятность исправить проблему:
|
||||
1. Включить в \"Настройки\" → RVX → Разное → Подмена потоковых данных → \"Использовать клиент JavaScript\".
|
||||
2. Изменить в \"Настройки\" → RVX → Разное → Подмена потоковых данных → \"Клиент по умолчанию\" на \"TV\" или \"TV простой\"."</string>
|
||||
Это может не работать для некоторых пользователей, если у вас это не работает:
|
||||
1. Перейдите в - RVX - Разное - Подмена потоковых данных и включите 'Использовать JavaScript-клиент'.
|
||||
2. Перейдите в - RVX - Разное - Подмена потоковых данных и измените 'Клиент по умолчанию' на 'TV'."</string>
|
||||
<string name="revanced_disable_auto_audio_tracks_title">Принудительные автоматические звуковые дорожки</string>
|
||||
<string name="revanced_disable_auto_captions_summary_off">Принудительные автоматические субтитры включены.</string>
|
||||
<string name="revanced_disable_auto_captions_summary_on">Принудительные автоматические субтитры отключены.</string>
|
||||
|
|
@ -922,11 +922,11 @@ Shorts
|
|||
<string name="revanced_hide_player_flyout_menu_ambient_mode_summary_off">Меню отображено.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_ambient_mode_summary_on">Меню скрыто.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_ambient_mode_title">Меню режима окружающей подсветки</string>
|
||||
<string name="revanced_hide_player_flyout_menu_audio_track_not_available">"Меню аудио скрыто.
|
||||
<string name="revanced_hide_player_flyout_menu_audio_track_not_available">"Меню звуковых дорожек скрыто.
|
||||
|
||||
Для отображения аудио меню нужно:
|
||||
1. Включить в \"Настройки\" → RVX → Разное → Подмена потоковых данных → \"Использовать клиент JavaScript\".
|
||||
2. Изменить в \"Настройки\" → RVX → Разное → Подмена потоковых данных → \"Клиент по умолчанию\" на \"TV\" или \"TV простой\"."</string>
|
||||
Чтобы отобразить меню звуковых дорожек:
|
||||
1. Перейдите в Настройки - RVX - Разное - Подмена потоковых данных и включите 'Использовать JavaScript-клиент'.
|
||||
2. Перейдите в Настройки - RVX - Разное - Подмена потоковых данных и измените 'Клиент по умолчанию' на 'TV'."</string>
|
||||
<string name="revanced_hide_player_flyout_menu_audio_track_summary_off">Меню \"Звуковая дорожка\" отображено.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_audio_track_summary_on">Меню \"Звуковая дорожка\" скрыто.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_audio_track_title">Меню \"Звуковая дорожка\"</string>
|
||||
|
|
@ -2386,7 +2386,7 @@ Shorts
|
|||
<small>(В разработке)</small>
|
||||
</string>
|
||||
<string name="revanced_spoof_streaming_data_client_entry_tv_legacy">"TV
|
||||
<small>(Устаревший)</small>"</string>
|
||||
<small>(Старый)</small>"</string>
|
||||
<string name="revanced_spoof_streaming_data_client_entry_tv_simply_no_potoken">"ТВ Простой
|
||||
<small>(Без PoToken)</small>"</string>
|
||||
<string name="revanced_spoof_streaming_data_client_entry_visionos">"visionOS
|
||||
|
|
@ -2679,15 +2679,9 @@ uBlock Origin обнаружил обход этой проблемы, вклю
|
|||
<string name="revanced_swipe_volume_title">Жест изменения громкости</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary">Примечание:\n• Если подмена кнопки не происходит, перезагрузите устройство.\n• Отключение этого параметра загружает больше рекламы со стороны сервера.\n• Чтобы видеореклама была видна, следует отключить этот параметр.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Кнопки \"Создать\" и \"Уведомления\" не поменяны местами.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Кнопки \"Создать\" и \"Уведомления\" поменяны местами.
|
||||
|
||||
Примечание: Включение опции принудительно скрывает видеорекламу."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">Кнопка \"Создать\" заменена на \"Уведомления\".</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Подмена кнопки \"Создать\" на \"Уведомления\"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Отключение этого параметра может привести к загрузке большего количества рекламы с сервера.
|
||||
|
||||
Кроме того, реклама больше не будет блокироваться в Shorts.
|
||||
|
||||
Если эта настройка не вступила в силу, попробуйте перейти в режим инкогнито."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">Если этот параметр не вступил в силу, попробуйте в режиме инкогнито.</string>
|
||||
<string name="revanced_theme_default">По умолчанию</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Предупреждение</string>
|
||||
|
|
|
|||
|
|
@ -2704,15 +2704,9 @@ uBlock Origin знайшов обхідний шлях для вирішення
|
|||
• Вимкнувши це налаштування, вантажиться більше реклами з боку сервера.
|
||||
• Ви повинні вимкнути це налаштування, щоб зробити відеорекламу видимою."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Кнопку Створити не міняється з кнопкою Сповіщення.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Кнопку Створити міняється з кнопкою Сповіщення.
|
||||
|
||||
Примітка: Увімкнення також примусово приховує відеорекламу."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">Кнопку Створити міняється з кнопкою Сповіщення.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Поміняти Створити зі Сповіщення</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Вимкнення може спричинити вантаження більше реклами з сервера.
|
||||
|
||||
А також, рекламу більше не блокуватиметься в Shorts.
|
||||
|
||||
Якщо це налаштування не діє, спробуйте перемкнути Анонімний режим."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">Якщо це налаштування не набуває чинності, спробуйте перемкнути в Анонімний режим.</string>
|
||||
<string name="revanced_theme_default">Стандартна</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Зауваження</string>
|
||||
|
|
|
|||
|
|
@ -599,9 +599,9 @@ Chi tiết:
|
|||
<string name="revanced_hide_ask_button_summary_off">Nút Hỏi được hiển thị.</string>
|
||||
<string name="revanced_hide_ask_button_summary_on">Nút Hỏi đã ẩn.</string>
|
||||
<string name="revanced_hide_ask_button_title">Ẩn nút Hỏi</string>
|
||||
<string name="revanced_hide_ask_section_summary_off">Phần đặt câu hỏi được hiển thị</string>
|
||||
<string name="revanced_hide_ask_section_summary_on">Phần đặt câu hỏi đã bị ẩn</string>
|
||||
<string name="revanced_hide_ask_section_title">Ẩn Đặt câu hỏi</string>
|
||||
<string name="revanced_hide_ask_section_summary_off">Phần Hỏi được hiển thị.</string>
|
||||
<string name="revanced_hide_ask_section_summary_on">Phần Hỏi đã ẩn.</string>
|
||||
<string name="revanced_hide_ask_section_title">Ẩn phần Hỏi</string>
|
||||
<string name="revanced_hide_attributes_section_summary_off">Phần Địa điểm nổi bật, Trò chơi, Âm nhạc, và Người được đề cập được hiển thị.</string>
|
||||
<string name="revanced_hide_attributes_section_summary_on">Phần Địa điểm nổi bật, Trò chơi, Âm nhạc, và Người được đề cập đã ẩn.</string>
|
||||
<string name="revanced_hide_attributes_section_title">Ẩn phần Thuộc tính</string>
|
||||
|
|
@ -713,6 +713,9 @@ Hạn chế: Các bình luận chữ xanh không dùng kiểu chữ mặc địn
|
|||
<string name="revanced_hide_community_posts_subscriptions_summary_off">Đã hiển thị trên thẻ Kênh đăng ký.</string>
|
||||
<string name="revanced_hide_community_posts_subscriptions_summary_on">Đã ẩn trên thẻ Kênh đăng ký.</string>
|
||||
<string name="revanced_hide_community_posts_subscriptions_title">Ẩn trên thẻ Kênh đăng ký</string>
|
||||
<string name="revanced_hide_creator_section_summary_off">Phần Nhà sáng tạo được hiển thị.</string>
|
||||
<string name="revanced_hide_creator_section_summary_on">Phần Nhà sáng tạo đã ẩn.</string>
|
||||
<string name="revanced_hide_creator_section_title">Ẩn phần Nhà sáng tạo</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_off">Kệ cửa hàng của nhà sáng tạo bên dưới video được hiển thị.</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_on">Kệ cửa hàng của nhà sáng tạo bên dưới video đã ẩn.</string>
|
||||
<string name="revanced_hide_creator_store_shelf_title">Ẩn kệ cửa hàng của nhà sáng tạo</string>
|
||||
|
|
@ -743,9 +746,12 @@ Cài đặt → Tự động phát/Phát → Tự động phát video tiếp the
|
|||
<string name="revanced_hide_expandable_shelf_summary_off">Kệ mở rộng được hiển thị.</string>
|
||||
<string name="revanced_hide_expandable_shelf_summary_on">Kệ mở rộng đã ẩn.</string>
|
||||
<string name="revanced_hide_expandable_shelf_title">Ẩn kệ mở rộng</string>
|
||||
<string name="revanced_hide_featured_section_summary_off">Phần nội dung nổi bật được hiển thị</string>
|
||||
<string name="revanced_hide_featured_section_summary_on">Phần nội dung nổi bật đã bị ẩn</string>
|
||||
<string name="revanced_hide_featured_section_title">Ẩn Nội dung nổi bật</string>
|
||||
<string name="revanced_hide_explore_podcast_section_summary_off">Phần Khám phá podcast được hiển thị.</string>
|
||||
<string name="revanced_hide_explore_podcast_section_summary_on">Phần Khám phá podcast đã ẩn.</string>
|
||||
<string name="revanced_hide_explore_podcast_section_title">Ẩn phần Khám phá podcast</string>
|
||||
<string name="revanced_hide_featured_section_summary_off">Phần Nội dung nổi bật trong phần Nhà sáng tạo được hiển thị.</string>
|
||||
<string name="revanced_hide_featured_section_summary_on">Phần Nội dung nổi bật trong phần Nhà sáng tạo đã ẩn.</string>
|
||||
<string name="revanced_hide_featured_section_title">Ẩn phần Nội dung nổi bật</string>
|
||||
<string name="revanced_hide_feed_captions_button_off">Nút Phụ đề được hiển thị.</string>
|
||||
<string name="revanced_hide_feed_captions_button_on">Nút Phụ đề đã ẩn.</string>
|
||||
<string name="revanced_hide_feed_captions_button_title">Ẩn nút Phụ đề</string>
|
||||
|
|
@ -781,9 +787,9 @@ Cài đặt → Tự động phát/Phát → Tự động phát video tiếp the
|
|||
<string name="revanced_hide_handle_summary_off">Tên hiển thị được hiển thị.</string>
|
||||
<string name="revanced_hide_handle_summary_on">Tên hiển thị đã ẩn.</string>
|
||||
<string name="revanced_hide_handle_title">Ẩn tên hiển thị</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Phần cách nội dung được tạo ra được hiển thị</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Phần cách nội dung được tạo ra đã bị ẩn</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Ẩn \'Cách nội dung này được tạo ra\'</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Phần Cách nội dung này được tạo ra được hiển thị.</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Phần Cách nội dung này được tạo ra đã ẩn.</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Ẩn phần Cách nội dung này được tạo ra</string>
|
||||
<string name="revanced_hide_hype_button_summary_off">Nút Khuấy động được hiển thị.</string>
|
||||
<string name="revanced_hide_hype_button_summary_on">Nút Khuấy động đã ẩn.</string>
|
||||
<string name="revanced_hide_hype_button_title">Ẩn nút Khuấy động</string>
|
||||
|
|
@ -1327,6 +1333,9 @@ Hạn chế: Tiêu đề chính thức trong kết quả tìm kiếm cũng sẽ
|
|||
<string name="revanced_hide_stop_ads_button_summary_off">Nút Ngừng quảng cáo được hiển thị.</string>
|
||||
<string name="revanced_hide_stop_ads_button_summary_on">Nút Ngừng quảng cáo đã ẩn.</string>
|
||||
<string name="revanced_hide_stop_ads_button_title">Ẩn Ngừng quảng cáo</string>
|
||||
<string name="revanced_hide_subscribe_button_summary_off">Nút đăng ký trong phần Nhà sáng tạo được hiển thị.</string>
|
||||
<string name="revanced_hide_subscribe_button_summary_on">Nút đăng ký trong phần Nhà sáng tạo đã ẩn.</string>
|
||||
<string name="revanced_hide_subscribe_button_title">Ẩn nút Đăng ký</string>
|
||||
<string name="revanced_hide_subscribed_channels_bar_summary_off">Thanh kênh đã đăng ký được hiển thị.</string>
|
||||
<string name="revanced_hide_subscribed_channels_bar_summary_on">Thanh kênh đã đăng ký đã ẩn.</string>
|
||||
<string name="revanced_hide_subscribed_channels_bar_title">Ẩn thanh kênh đã đăng ký</string>
|
||||
|
|
@ -1357,6 +1366,11 @@ Hạn chế: Tiêu đề chính thức trong kết quả tìm kiếm cũng sẽ
|
|||
<string name="revanced_hide_toolbar_notification_button_summary_off">Nút Thông báo được hiển thị.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_summary_on">Nút Thông báo đã ẩn.</string>
|
||||
<string name="revanced_hide_toolbar_notification_button_title">Ẩn nút Thông báo</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_off">Nút Tìm kiếm được hiển thị.</string>
|
||||
<string name="revanced_hide_toolbar_search_button_summary_on">"Nút Tìm kiếm đã ẩn.
|
||||
|
||||
Cài đặt này có thể không hoạt động nếu thanh tìm kiếm rộng đang bật."</string>
|
||||
<string name="revanced_hide_toolbar_search_button_title">Ẩn nút Tìm kiếm</string>
|
||||
<string name="revanced_hide_transcript_section_summary_off">Phần Bản chép lời được hiển thị.</string>
|
||||
<string name="revanced_hide_transcript_section_summary_on">Phần Bản chép lời đã ẩn.</string>
|
||||
<string name="revanced_hide_transcript_section_title">Ẩn phần Bản chép lời</string>
|
||||
|
|
@ -1906,6 +1920,13 @@ Tuỳ chọn này chỉ tự động chấp nhận hộp thoại cảnh báo, ch
|
|||
<string name="revanced_replace_channel_handle_summary_off">Tên hiển thị của kênh (@handle) đang được áp dụng.</string>
|
||||
<string name="revanced_replace_channel_handle_summary_on">Tên kênh đang được áp dụng.</string>
|
||||
<string name="revanced_replace_channel_handle_title">Thay thế tên hiển thị của kênh</string>
|
||||
<string name="revanced_replace_navigation_button_summary">Đổi chỗ nút điều hướng với nút Tìm kiếm.</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_home">Trang chủ</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_notifications">Thông báo</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_shorts">Shorts</string>
|
||||
<string name="revanced_replace_navigation_button_target_entry_subscriptions">Kênh đăng ký</string>
|
||||
<string name="revanced_replace_navigation_button_target_title">Thay thế nút điều hướng</string>
|
||||
<string name="revanced_replace_navigation_button_title">Thay thế nút điều hướng</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_off">Nhấn để hiển thị thời gian còn lại.</string>
|
||||
<string name="revanced_replace_time_stamp_action_summary_on">Nhấn để mở mục Tốc độ phát hoặc Chất lượng video.</string>
|
||||
<string name="revanced_replace_time_stamp_action_title">Thay thế chức năng của dấu thời gian</string>
|
||||
|
|
@ -2352,6 +2373,7 @@ Lưu ý:\n- Tuỳ chọn này sẽ thay đổi giao diện ứng dụng, tuy nhi
|
|||
<string name="revanced_spoof_app_version_target_entry_19_28_42">19.28.42 - Khôi phục tiêu đề danh sách phát kiểu cũ</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_19_33_37">19.33.37 - Khôi phục bảng trình đơn tốc độ phát cũ</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_05_46">20.05.46 - Khôi phục tính năng bản chép lời</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_20_13_41">20.13.41 - Khôi phục thanh thao tác video mở rộng</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_title">Phiên bản giả mạo</string>
|
||||
<string name="revanced_spoof_app_version_target_invalid_toast">Phiên bản ứng dụng đã chọn không hợp lệ: %s.</string>
|
||||
<string name="revanced_spoof_app_version_target_summary">Nhập phiên bản giả mạo mà bạn muốn hướng tới.</string>
|
||||
|
|
@ -2700,15 +2722,9 @@ Tua video bằng cách vuốt ngang nửa trên màn hình."</string>
|
|||
• Tắt tuỳ chọn này sẽ tải thêm quảng cáo từ phía máy chủ.
|
||||
• Tắt tuỳ chọn này có thể hiển thị quảng cáo dạng video."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Nút Tạo và nút Thông báo như mặc định.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"Nút Tạo đã được đổi vị trí với nút Thông báo.
|
||||
|
||||
Lưu ý: Bật tuỳ chọn này cũng sẽ ẩn các quảng cáo dạng video."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">Nút Tạo đã đổi chỗ với nút Thông báo.</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Hoán đổi nút Tạo và nút Thông báo</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"Tắt tùy chọn này có thể tải thêm quảng cáo từ máy chủ.
|
||||
|
||||
Ngoài ra, quảng cáo sẽ không còn bị chặn trong trình phát Shorts.
|
||||
|
||||
Nếu cài đặt này không có hiệu lực, hãy thử chuyển sang chế độ Ẩn danh."</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">Nếu cài đặt này không có hiệu lực, hãy thử chuyển sang Chế độ ẩn danh.</string>
|
||||
<string name="revanced_theme_default">Nguyên bản</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Chú ý</string>
|
||||
|
|
|
|||
|
|
@ -2689,15 +2689,13 @@ yt-dlp的外部JavaScript(yt-dlp-ejs)用于解密最新播放器JavaScript
|
|||
• 禁用此设置会从服务器端加载更多广告
|
||||
• 你应该禁用此设置以显示视频广告"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">创建按钮未替换为通知按钮</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"创建按钮替换为通知按钮
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"创作按钮将切换成通知按钮
|
||||
|
||||
注意:启用此选项也强制隐藏视频广告"</string>
|
||||
注意:启用此功能也会强制隐藏视频广告"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">交换创建和通知按钮</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"禁用此功能可能会从服务器加载更多广告
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"禁用此设置也会禁用 Shorts 广告拦截。
|
||||
|
||||
此外,Shorts 中的广告将不再被屏蔽
|
||||
|
||||
如果此设置未生效,请尝试切换到隐身模式"</string>
|
||||
如果更改此设置未生效,请尝试切换到无痕模式。"</string>
|
||||
<string name="revanced_theme_default">原版</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">警告</string>
|
||||
|
|
|
|||
|
|
@ -2723,15 +2723,13 @@ yt-dlp 的外部 JavaScript (yt-dlp-ejs) 用於在最新播放器 JavaScript 中
|
|||
• 停用這項設定會從伺服器端載入更多廣告
|
||||
• 你應該停用這項設定以顯示影片廣告"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">「建立」按鈕未與「通知」按鈕交換。</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"「建立」按鈕已與「通知」按鈕交換。
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">"「建立」按鈕與「通知」按鈕對調
|
||||
|
||||
注意:啟用此功能也會強制隱藏影片廣告。"</string>
|
||||
注意:啟用此功能也會強制隱藏影片廣告"</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_title">交換創作和通知按鈕</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"停用此功能可能會從伺服器載入更多廣告。
|
||||
<string name="revanced_switch_create_with_notifications_button_user_dialog_message">"停用此設定也會停用 Shorts 的廣告攔截功能。
|
||||
|
||||
此外,廣告將不再在 Shorts 中被封鎖。
|
||||
|
||||
若此設定未生效,請嘗試切換至無痕模式。"</string>
|
||||
如果變更此設定沒有生效,請試試看切換到無痕模式。"</string>
|
||||
<string name="revanced_theme_default">預設</string>
|
||||
<string name="revanced_third_party_youtube_music_dialog_title">RVX 音樂</string>
|
||||
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">警告</string>
|
||||
|
|
|
|||
Loading…
Reference in a new issue