This commit is contained in:
Aaron Veil 2025-11-20 09:42:20 +03:00
parent 91577930ed
commit ab3f98cb31
60 changed files with 1594 additions and 413 deletions

View file

@ -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,
)

View file

@ -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

View file

@ -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() {

View file

@ -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

View file

@ -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) {

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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) {

View file

@ -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);
}
}
}

View file

@ -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)
);
}

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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() {

View file

@ -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);

View file

@ -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();

View file

@ -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

View file

@ -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"
}
}

View file

@ -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"
}
)

View file

@ -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),
)

View file

@ -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
)
}
}

View file

@ -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(

View file

@ -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

View file

@ -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),
)

View file

@ -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(

View file

@ -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),

View file

@ -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

View file

@ -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",

View file

@ -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) {

View file

@ -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",

View file

@ -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",

View file

@ -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))
)
)
}
}
}

View file

@ -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(

View file

@ -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)

View file

@ -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")

View file

@ -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>

View file

@ -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>

View file

@ -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" />

View file

@ -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" />

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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" />

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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">Ψευδώνυμο &amp; διεύθυνση 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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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.

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -2689,15 +2689,13 @@ yt-dlp的外部JavaScriptyt-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>

View file

@ -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>