mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-04-30 06:34:28 +02:00
Compare commits
9 Commits
main
...
v5.22.0-de
Author | SHA1 | Date | |
---|---|---|---|
![]() |
903cdb9bb3 | ||
![]() |
ab4bdc8a25 | ||
![]() |
1d5c6c9351 | ||
![]() |
06b35b2a7d | ||
![]() |
a1207c9784 | ||
![]() |
f198bece65 | ||
![]() |
f459c3c7fa | ||
![]() |
39769bf384 | ||
![]() |
c255ac18e0 |
27
CHANGELOG.md
27
CHANGELOG.md
@ -1,3 +1,30 @@
|
|||||||
|
# [5.22.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.22.0-dev.2...v5.22.0-dev.3) (2025-04-29)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube - GmsCore support:** Show troubleshooting in app text if the user recently changed their account details ([#4879](https://github.com/ReVanced/revanced-patches/issues/4879)) ([ab4bdc8](https://github.com/ReVanced/revanced-patches/commit/ab4bdc8a2519cee15f79bf95d89e7ea56ea464ee))
|
||||||
|
|
||||||
|
# [5.22.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.22.0-dev.1...v5.22.0-dev.2) (2025-04-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Shorts autoplay:** Fix autoplay with YT 20.12 ([06b35b2](https://github.com/ReVanced/revanced-patches/commit/06b35b2a7d7371915881e8f430c32ce15fa224de))
|
||||||
|
|
||||||
|
# [5.22.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.21.0...v5.22.0-dev.1) (2025-04-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **TikTok - Feed filter:** Hide ads in following feed ([#4844](https://github.com/ReVanced/revanced-patches/issues/4844)) ([c255ac1](https://github.com/ReVanced/revanced-patches/commit/c255ac18e0b2dcf917bd0559876be5a2a81023db))
|
||||||
|
* **YouTube - Spoof app version:** Do not hide spoof version in general settings menu ([#4861](https://github.com/ReVanced/revanced-patches/issues/4861)) ([f459c3c](https://github.com/ReVanced/revanced-patches/commit/f459c3c7fae3a1b8addf3354488dcef9f95255cc))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **TikTok - Feed Filter:** Remove TikTok Shop from feed. ([#4851](https://github.com/ReVanced/revanced-patches/issues/4851)) ([f198bec](https://github.com/ReVanced/revanced-patches/commit/f198bece653e3e1adf083129dedb77c1d1a633d7))
|
||||||
|
|
||||||
# [5.21.0](https://github.com/ReVanced/revanced-patches/compare/v5.20.1...v5.21.0) (2025-04-25)
|
# [5.21.0](https://github.com/ReVanced/revanced-patches/compare/v5.20.1...v5.21.0) (2025-04-25)
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,9 +20,7 @@ import androidx.annotation.RequiresApi;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
@SuppressWarnings("unused")
|
||||||
* @noinspection unused
|
|
||||||
*/
|
|
||||||
public class GmsCoreSupport {
|
public class GmsCoreSupport {
|
||||||
private static final String PACKAGE_NAME_YOUTUBE = "com.google.android.youtube";
|
private static final String PACKAGE_NAME_YOUTUBE = "com.google.android.youtube";
|
||||||
private static final String PACKAGE_NAME_YOUTUBE_MUSIC = "com.google.android.apps.youtube.music";
|
private static final String PACKAGE_NAME_YOUTUBE_MUSIC = "com.google.android.apps.youtube.music";
|
||||||
|
@ -2,6 +2,7 @@ package app.revanced.extension.tiktok.feedfilter;
|
|||||||
|
|
||||||
import com.ss.android.ugc.aweme.feed.model.Aweme;
|
import com.ss.android.ugc.aweme.feed.model.Aweme;
|
||||||
import com.ss.android.ugc.aweme.feed.model.FeedItemList;
|
import com.ss.android.ugc.aweme.feed.model.FeedItemList;
|
||||||
|
import com.ss.android.ugc.aweme.follow.presenter.FollowFeedList;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -13,22 +14,41 @@ public final class FeedItemsFilter {
|
|||||||
new StoryFilter(),
|
new StoryFilter(),
|
||||||
new ImageVideoFilter(),
|
new ImageVideoFilter(),
|
||||||
new ViewCountFilter(),
|
new ViewCountFilter(),
|
||||||
new LikeCountFilter()
|
new LikeCountFilter(),
|
||||||
|
new ShopFilter()
|
||||||
);
|
);
|
||||||
|
|
||||||
public static void filter(FeedItemList feedItemList) {
|
public static void filter(FeedItemList feedItemList) {
|
||||||
Iterator<Aweme> feedItemListIterator = feedItemList.items.iterator();
|
filterFeedList(feedItemList.items, item -> item);
|
||||||
while (feedItemListIterator.hasNext()) {
|
}
|
||||||
Aweme item = feedItemListIterator.next();
|
|
||||||
if (item == null) continue;
|
|
||||||
|
|
||||||
|
public static void filter(FollowFeedList followFeedList) {
|
||||||
|
filterFeedList(followFeedList.mItems, feed -> (feed != null) ? feed.aweme : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> void filterFeedList(List<T> list, AwemeExtractor<T> extractor) {
|
||||||
|
// Could be simplified with removeIf() but requires Android 7.0+ while TikTok supports 4.0+.
|
||||||
|
Iterator<T> iterator = list.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
T container = iterator.next();
|
||||||
|
Aweme item = extractor.extract(container);
|
||||||
|
if (item != null && shouldFilter(item)) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean shouldFilter(Aweme item) {
|
||||||
for (IFilter filter : FILTERS) {
|
for (IFilter filter : FILTERS) {
|
||||||
boolean enabled = filter.getEnabled();
|
if (filter.getEnabled() && filter.getFiltered(item)) {
|
||||||
if (enabled && filter.getFiltered(item)) {
|
return true;
|
||||||
feedItemListIterator.remove();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
interface AwemeExtractor<T> {
|
||||||
|
Aweme extract(T source);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package app.revanced.extension.tiktok.feedfilter;
|
||||||
|
|
||||||
|
import app.revanced.extension.tiktok.settings.Settings;
|
||||||
|
import com.ss.android.ugc.aweme.feed.model.Aweme;
|
||||||
|
|
||||||
|
public class ShopFilter implements IFilter {
|
||||||
|
private static final String SHOP_INFO = "placeholder_product_id";
|
||||||
|
@Override
|
||||||
|
public boolean getEnabled() {
|
||||||
|
return Settings.HIDE_SHOP.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getFiltered(Aweme item) {
|
||||||
|
return item.getShareUrl().contains(SHOP_INFO);
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import app.revanced.extension.shared.settings.StringSetting;
|
|||||||
public class Settings extends BaseSettings {
|
public class Settings extends BaseSettings {
|
||||||
public static final BooleanSetting REMOVE_ADS = new BooleanSetting("remove_ads", TRUE, true);
|
public static final BooleanSetting REMOVE_ADS = new BooleanSetting("remove_ads", TRUE, true);
|
||||||
public static final BooleanSetting HIDE_LIVE = new BooleanSetting("hide_live", FALSE, true);
|
public static final BooleanSetting HIDE_LIVE = new BooleanSetting("hide_live", FALSE, true);
|
||||||
|
public static final BooleanSetting HIDE_SHOP = new BooleanSetting("hide_shop", FALSE, true);
|
||||||
public static final BooleanSetting HIDE_STORY = new BooleanSetting("hide_story", FALSE, true);
|
public static final BooleanSetting HIDE_STORY = new BooleanSetting("hide_story", FALSE, true);
|
||||||
public static final BooleanSetting HIDE_IMAGE = new BooleanSetting("hide_image", FALSE, true);
|
public static final BooleanSetting HIDE_IMAGE = new BooleanSetting("hide_image", FALSE, true);
|
||||||
public static final StringSetting MIN_MAX_VIEWS = new StringSetting("min_max_views", "0-" + Long.MAX_VALUE, true);
|
public static final StringSetting MIN_MAX_VIEWS = new StringSetting("min_max_views", "0-" + Long.MAX_VALUE, true);
|
||||||
|
@ -26,6 +26,11 @@ public class FeedFilterPreferenceCategory extends ConditionalPreferenceCategory
|
|||||||
"Remove feed ads", "Remove ads from feed.",
|
"Remove feed ads", "Remove ads from feed.",
|
||||||
Settings.REMOVE_ADS
|
Settings.REMOVE_ADS
|
||||||
));
|
));
|
||||||
|
addPreference(new TogglePreference(
|
||||||
|
context,
|
||||||
|
"Hide TikTok Shop", "Hide TikTok shop from feed.",
|
||||||
|
Settings.HIDE_SHOP
|
||||||
|
));
|
||||||
addPreference(new TogglePreference(
|
addPreference(new TogglePreference(
|
||||||
context,
|
context,
|
||||||
"Hide livestreams", "Hide livestreams from feed.",
|
"Hide livestreams", "Hide livestreams from feed.",
|
||||||
|
@ -33,4 +33,8 @@ public class Aweme {
|
|||||||
public AwemeStatistics getStatistics() {
|
public AwemeStatistics getStatistics() {
|
||||||
throw new UnsupportedOperationException("Stub");
|
throw new UnsupportedOperationException("Stub");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getShareUrl() {
|
||||||
|
throw new UnsupportedOperationException("Stub");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.ss.android.ugc.aweme.follow.presenter;
|
||||||
|
|
||||||
|
import com.ss.android.ugc.aweme.feed.model.Aweme;
|
||||||
|
|
||||||
|
//Dummy class
|
||||||
|
public class FollowFeed {
|
||||||
|
public Aweme aweme;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.ss.android.ugc.aweme.follow.presenter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
//Dummy class
|
||||||
|
public class FollowFeedList {
|
||||||
|
public List<FollowFeed> mItems;
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package app.revanced.extension.youtube.patches;
|
||||||
|
|
||||||
|
import static app.revanced.extension.shared.StringRef.sf;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.Utils;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class AccountCredentialsInvalidTextPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static String getOfflineNetworkErrorString(String original) {
|
||||||
|
try {
|
||||||
|
if (Utils.isNetworkConnected()) {
|
||||||
|
Logger.printDebug(() -> "Network appears to be online, but app is showing offline error");
|
||||||
|
return '\n' + sf("microg_offline_account_login_error").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.printDebug(() -> "Network is offline");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "getOfflineNetworkErrorString failure", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@ package app.revanced.extension.youtube.patches;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -76,7 +78,7 @@ public class ShortsAutoplayPatch {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static Enum<?> changeShortsRepeatBehavior(Enum<?> original) {
|
public static Enum<?> changeShortsRepeatBehavior(@Nullable Enum<?> original) {
|
||||||
try {
|
try {
|
||||||
final boolean autoplay;
|
final boolean autoplay;
|
||||||
|
|
||||||
@ -98,17 +100,35 @@ public class ShortsAutoplayPatch {
|
|||||||
: ShortsLoopBehavior.REPEAT;
|
: ShortsLoopBehavior.REPEAT;
|
||||||
|
|
||||||
if (behavior.ytEnumValue != null) {
|
if (behavior.ytEnumValue != null) {
|
||||||
Logger.printDebug(() -> behavior.ytEnumValue == original
|
Logger.printDebug(() -> {
|
||||||
? "Changing Shorts repeat behavior from: " + original.name() + " to: " + behavior.ytEnumValue
|
String name = (original == null ? "unknown (null)" : original.name());
|
||||||
: "Behavior setting is same as original. Using original: " + original.name()
|
return behavior == original
|
||||||
);
|
? "Behavior setting is same as original. Using original: " + name
|
||||||
|
: "Changing Shorts repeat behavior from: " + name + " to: " + behavior.name();
|
||||||
|
});
|
||||||
|
|
||||||
return behavior.ytEnumValue;
|
return behavior.ytEnumValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (original == null) {
|
||||||
|
// Cannot return null, as null is used to indicate Short was auto played.
|
||||||
|
// Unpatched app replaces null with unknown enum type (appears to fix for bad api data).
|
||||||
|
Enum<?> unknown = ShortsLoopBehavior.UNKNOWN.ytEnumValue;
|
||||||
|
Logger.printDebug(() -> "Original is null, returning: " + unknown.name());
|
||||||
|
return unknown;
|
||||||
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.printException(() -> "changeShortsRepeatState failure", ex);
|
Logger.printException(() -> "changeShortsRepeatBehavior failure", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean isAutoPlay(Enum<?> original) {
|
||||||
|
return ShortsLoopBehavior.SINGLE_PLAY.ytEnumValue == original;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
|
|||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
android.useAndroidX = true
|
android.useAndroidX = true
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 5.21.0
|
version = 5.22.0-dev.3
|
||||||
|
@ -642,14 +642,12 @@ public abstract class app/revanced/patches/shared/misc/settings/preference/BaseP
|
|||||||
public static final field Companion Lapp/revanced/patches/shared/misc/settings/preference/BasePreference$Companion;
|
public static final field Companion Lapp/revanced/patches/shared/misc/settings/preference/BasePreference$Companion;
|
||||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
|
||||||
public final fun getIcon ()Ljava/lang/String;
|
public final fun getIcon ()Ljava/lang/String;
|
||||||
public final fun getKey ()Ljava/lang/String;
|
public final fun getKey ()Ljava/lang/String;
|
||||||
public final fun getLayout ()Ljava/lang/String;
|
public final fun getLayout ()Ljava/lang/String;
|
||||||
public final fun getSummaryKey ()Ljava/lang/String;
|
public final fun getSummaryKey ()Ljava/lang/String;
|
||||||
public final fun getTag ()Ljava/lang/String;
|
public final fun getTag ()Ljava/lang/String;
|
||||||
public final fun getTitleKey ()Ljava/lang/String;
|
public final fun getTitleKey ()Ljava/lang/String;
|
||||||
public fun hashCode ()I
|
|
||||||
public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element;
|
public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,26 +51,6 @@ abstract class BasePreference(
|
|||||||
layout?.let { setAttribute("android:layout", layout) }
|
layout?.let { setAttribute("android:layout", layout) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = key?.hashCode() ?: 0
|
|
||||||
result = 31 * result + titleKey.hashCode()
|
|
||||||
result = 31 * result + tag.hashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (javaClass != other?.javaClass) return false
|
|
||||||
|
|
||||||
other as BasePreference
|
|
||||||
|
|
||||||
if (key != other.key) return false
|
|
||||||
if (titleKey != other.titleKey) return false
|
|
||||||
if (tag != other.tag) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun Element.addSummary(summaryKey: String, summaryType: SummaryType = SummaryType.DEFAULT) =
|
fun Element.addSummary(summaryKey: String, summaryType: SummaryType = SummaryType.DEFAULT) =
|
||||||
setAttribute("android:${summaryType.type}", "@string/$summaryKey")
|
setAttribute("android:${summaryType.type}", "@string/$summaryKey")
|
||||||
|
@ -9,6 +9,8 @@ import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint
|
|||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/tiktok/feedfilter/FeedItemsFilter;"
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val feedFilterPatch = bytecodePatch(
|
val feedFilterPatch = bytecodePatch(
|
||||||
name = "Feed filter",
|
name = "Feed filter",
|
||||||
@ -26,14 +28,15 @@ val feedFilterPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
feedApiServiceLIZFingerprint.method.apply {
|
arrayOf(
|
||||||
val returnFeedItemInstruction = instructions.first { it.opcode == Opcode.RETURN_OBJECT }
|
feedApiServiceLIZFingerprint.method to "$EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;)V",
|
||||||
val feedItemsRegister = (returnFeedItemInstruction as OneRegisterInstruction).registerA
|
followFeedFingerprint.method to "$EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;)V"
|
||||||
|
).forEach { (method, filterSignature) ->
|
||||||
addInstruction(
|
val returnInstruction = method.instructions.first { it.opcode == Opcode.RETURN_OBJECT }
|
||||||
returnFeedItemInstruction.location.index,
|
val register = (returnInstruction as OneRegisterInstruction).registerA
|
||||||
"invoke-static { v$feedItemsRegister }, " +
|
method.addInstruction(
|
||||||
"Lapp/revanced/extension/tiktok/feedfilter/FeedItemsFilter;->filter(Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;)V",
|
returnInstruction.location.index,
|
||||||
|
"invoke-static { v$register }, $filterSignature"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,4 +45,5 @@ val feedFilterPatch = bytecodePatch(
|
|||||||
"invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableFeedFilter()V",
|
"invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableFeedFilter()V",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,22 @@
|
|||||||
package app.revanced.patches.tiktok.feedfilter
|
package app.revanced.patches.tiktok.feedfilter
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint
|
import app.revanced.patcher.fingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
internal val feedApiServiceLIZFingerprint = fingerprint {
|
internal val feedApiServiceLIZFingerprint = fingerprint {
|
||||||
custom { method, classDef ->
|
custom { method, classDef ->
|
||||||
classDef.endsWith("/FeedApiService;") && method.name == "fetchFeedList"
|
classDef.endsWith("/FeedApiService;") && method.name == "fetchFeedList"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val followFeedFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
||||||
|
returns("Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;")
|
||||||
|
strings("getFollowFeedList")
|
||||||
|
opcodes(
|
||||||
|
Opcode.INVOKE_INTERFACE_RANGE,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_INTERFACE
|
||||||
|
)
|
||||||
|
}
|
@ -1,8 +1,13 @@
|
|||||||
package app.revanced.patches.youtube.layout.shortsautoplay
|
package app.revanced.patches.youtube.layout.shortsautoplay
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint
|
import app.revanced.patcher.fingerprint
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstruction
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
internal val reelEnumConstructorFingerprint = fingerprint {
|
internal val reelEnumConstructorFingerprint = fingerprint {
|
||||||
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
|
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
|
||||||
@ -20,3 +25,27 @@ internal val reelPlaybackRepeatFingerprint = fingerprint {
|
|||||||
parameters("L")
|
parameters("L")
|
||||||
strings("YoutubePlayerState is in throwing an Error.")
|
strings("YoutubePlayerState is in throwing an Error.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val reelPlaybackFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||||
|
returns("V")
|
||||||
|
parameters("J")
|
||||||
|
custom { method, _ ->
|
||||||
|
indexOfMilliSecondsInstruction(method) >= 0 &&
|
||||||
|
indexOfInitializationInstruction(method) >= 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun indexOfMilliSecondsInstruction(method: Method) =
|
||||||
|
method.indexOfFirstInstruction {
|
||||||
|
getReference<FieldReference>()?.name == "MILLISECONDS"
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun indexOfInitializationInstruction(method: Method) =
|
||||||
|
method.indexOfFirstInstruction {
|
||||||
|
val reference = getReference<MethodReference>()
|
||||||
|
opcode == Opcode.INVOKE_DIRECT &&
|
||||||
|
reference?.name == "<init>" &&
|
||||||
|
reference.parameterTypes.size == 3 &&
|
||||||
|
reference.parameterTypes.firstOrNull() == "I"
|
||||||
|
}
|
||||||
|
@ -2,21 +2,32 @@ package app.revanced.patches.youtube.layout.shortsautoplay
|
|||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
import app.revanced.patches.all.misc.resources.addResources
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
||||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||||
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
|
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
|
||||||
|
import app.revanced.patches.youtube.misc.playservice.is_20_09_or_greater
|
||||||
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||||
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
|
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
|
||||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
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.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||||
|
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||||
|
|
||||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ShortsAutoplayPatch;"
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ShortsAutoplayPatch;"
|
||||||
|
|
||||||
@ -98,5 +109,84 @@ val shortsAutoplayPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// As of YouTube 20.09, Google has removed the code for 'Autoplay' and 'Pause' from this method.
|
||||||
|
// Manually restore the removed 'Autoplay' code.
|
||||||
|
if (is_20_09_or_greater) {
|
||||||
|
// Variable names are only a rough guess of what these methods do.
|
||||||
|
val userActionMethodIndex = indexOfInitializationInstruction(reelPlaybackFingerprint.method)
|
||||||
|
val userActionMethodReference = reelPlaybackFingerprint.method
|
||||||
|
.getInstruction<ReferenceInstruction>(userActionMethodIndex).reference as MethodReference
|
||||||
|
val reelSequenceControllerMethodIndex = reelPlaybackFingerprint.method
|
||||||
|
.indexOfFirstInstructionOrThrow(userActionMethodIndex, Opcode.INVOKE_VIRTUAL)
|
||||||
|
val reelSequenceControllerMethodReference = reelPlaybackFingerprint.method
|
||||||
|
.getInstruction<ReferenceInstruction>(reelSequenceControllerMethodIndex).reference as MethodReference
|
||||||
|
|
||||||
|
reelPlaybackRepeatFingerprint.method.apply {
|
||||||
|
// Find the first call modified by extension code above.
|
||||||
|
val extensionReturnResultIndex = indexOfFirstInstructionOrThrow {
|
||||||
|
opcode == Opcode.INVOKE_STATIC &&
|
||||||
|
getReference<MethodReference>()?.definingClass == EXTENSION_CLASS_DESCRIPTOR
|
||||||
|
} + 1
|
||||||
|
val enumRegister = getInstruction<OneRegisterInstruction>(extensionReturnResultIndex).registerA
|
||||||
|
val getReelSequenceControllerIndex = indexOfFirstInstructionOrThrow(extensionReturnResultIndex) {
|
||||||
|
val reference = getReference<FieldReference>()
|
||||||
|
opcode == Opcode.IGET_OBJECT &&
|
||||||
|
reference?.definingClass == definingClass &&
|
||||||
|
reference.type == reelSequenceControllerMethodReference.definingClass
|
||||||
|
}
|
||||||
|
val getReelSequenceControllerReference =
|
||||||
|
getInstruction<ReferenceInstruction>(getReelSequenceControllerIndex).reference
|
||||||
|
|
||||||
|
// Add a helper method to avoid finding multiple free registers.
|
||||||
|
// If enum is autoplay then method performs autoplay and returns null,
|
||||||
|
// otherwise returns the same enum.
|
||||||
|
val helperClass = definingClass
|
||||||
|
val helperName = "patch_handleAutoPlay"
|
||||||
|
val helperReturnType = "Ljava/lang/Enum;"
|
||||||
|
val helperMethod = ImmutableMethod(
|
||||||
|
helperClass,
|
||||||
|
helperName,
|
||||||
|
listOf(ImmutableMethodParameter("Ljava/lang/Enum;", null, null)),
|
||||||
|
helperReturnType,
|
||||||
|
AccessFlags.PRIVATE.value,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
MutableMethodImplementation(7),
|
||||||
|
).toMutable().apply {
|
||||||
|
addInstructionsWithLabels(
|
||||||
|
0,
|
||||||
|
"""
|
||||||
|
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->isAutoPlay(Ljava/lang/Enum;)Z
|
||||||
|
move-result v0
|
||||||
|
if-eqz v0, :ignore
|
||||||
|
new-instance v0, ${userActionMethodReference.definingClass}
|
||||||
|
const/4 v1, 0x3
|
||||||
|
const/4 v2, 0x0
|
||||||
|
invoke-direct { v0, v1, v2, v2 }, $userActionMethodReference
|
||||||
|
iget-object v3, p0, $getReelSequenceControllerReference
|
||||||
|
invoke-virtual { v3, v0 }, $reelSequenceControllerMethodReference
|
||||||
|
const/4 v4, 0x0
|
||||||
|
return-object v4
|
||||||
|
:ignore
|
||||||
|
return-object p1
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
reelPlaybackRepeatFingerprint.classDef.methods.add(helperMethod)
|
||||||
|
|
||||||
|
addInstructionsWithLabels(
|
||||||
|
extensionReturnResultIndex + 1,
|
||||||
|
"""
|
||||||
|
invoke-direct { p0, v$enumRegister }, $helperClass->$helperName(Ljava/lang/Enum;)$helperReturnType
|
||||||
|
move-result-object v$enumRegister
|
||||||
|
if-nez v$enumRegister, :ignore
|
||||||
|
return-void # Autoplay was performed.
|
||||||
|
:ignore
|
||||||
|
nop
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ val spoofAppVersionPatch = bytecodePatch(
|
|||||||
|
|
||||||
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||||
// Group the switch and list preference together, since General menu is sorted by name
|
// Group the switch and list preference together, since General menu is sorted by name
|
||||||
// and the preferences can be scattered apart with non English langauges.
|
// and the preferences can be scattered apart with non English languages.
|
||||||
PreferenceCategory(
|
PreferenceCategory(
|
||||||
titleKey = null,
|
titleKey = null,
|
||||||
sorting = Sorting.UNSORTED,
|
sorting = Sorting.UNSORTED,
|
||||||
@ -122,12 +122,12 @@ val spoofAppVersionPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val insertIndex = spoofAppVersionFingerprint.patternMatch!!.startIndex + 1
|
spoofAppVersionFingerprint.apply {
|
||||||
val buildOverrideNameRegister =
|
val startIndex = patternMatch!!.startIndex
|
||||||
spoofAppVersionFingerprint.method.getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
val buildOverrideNameRegister = method.getInstruction<OneRegisterInstruction>(startIndex).registerA
|
||||||
|
|
||||||
spoofAppVersionFingerprint.method.addInstructions(
|
method.addInstructions(
|
||||||
insertIndex,
|
startIndex + 1,
|
||||||
"""
|
"""
|
||||||
invoke-static {v$buildOverrideNameRegister}, $EXTENSION_CLASS_DESCRIPTOR->getYouTubeVersionOverride(Ljava/lang/String;)Ljava/lang/String;
|
invoke-static {v$buildOverrideNameRegister}, $EXTENSION_CLASS_DESCRIPTOR->getYouTubeVersionOverride(Ljava/lang/String;)Ljava/lang/String;
|
||||||
move-result-object v$buildOverrideNameRegister
|
move-result-object v$buildOverrideNameRegister
|
||||||
@ -135,3 +135,4 @@ val spoofAppVersionPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.gms
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
|
import app.revanced.patches.shared.misc.mapping.get
|
||||||
|
import app.revanced.patches.shared.misc.mapping.resourceMappings
|
||||||
|
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
|
"Lapp/revanced/extension/youtube/patches/AccountCredentialsInvalidTextPatch;"
|
||||||
|
|
||||||
|
internal var ic_offline_no_content_upside_down = -1L
|
||||||
|
private set
|
||||||
|
internal var offline_no_content_body_text_not_offline_eligible = -1L
|
||||||
|
private set
|
||||||
|
|
||||||
|
private val accountCredentialsInvalidTextResourcePatch = resourcePatch {
|
||||||
|
execute {
|
||||||
|
ic_offline_no_content_upside_down = resourceMappings[
|
||||||
|
"drawable",
|
||||||
|
"ic_offline_no_content_upside_down"
|
||||||
|
]
|
||||||
|
|
||||||
|
offline_no_content_body_text_not_offline_eligible = resourceMappings[
|
||||||
|
"string",
|
||||||
|
"offline_no_content_body_text_not_offline_eligible"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val accountCredentialsInvalidTextPatch = bytecodePatch {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
accountCredentialsInvalidTextResourcePatch,
|
||||||
|
addResourcesPatch
|
||||||
|
)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
addResources("youtube", "misc.gms.accountCredentialsInvalidTextPatch")
|
||||||
|
|
||||||
|
// If the user recently changed their account password,
|
||||||
|
// the app can show "You're offline. Check your internet connection."
|
||||||
|
// even when the internet is available. For this situation
|
||||||
|
// YouTube + MicroG shows an offline error message.
|
||||||
|
//
|
||||||
|
// Change the error text to inform the user to uninstall and reinstall MicroG.
|
||||||
|
// The user can also fix this by deleting the MicroG account but
|
||||||
|
// MicroG accounts look almost identical to Google device accounts
|
||||||
|
// and it's more foolproof to instead uninstall/reinstall.
|
||||||
|
arrayOf(
|
||||||
|
specificNetworkErrorViewControllerFingerprint,
|
||||||
|
loadingFrameLayoutControllerFingerprint
|
||||||
|
).forEach { fingerprint ->
|
||||||
|
fingerprint.method.apply {
|
||||||
|
val resourceIndex = indexOfFirstLiteralInstructionOrThrow(
|
||||||
|
offline_no_content_body_text_not_offline_eligible
|
||||||
|
)
|
||||||
|
val getStringIndex = indexOfFirstInstructionOrThrow(resourceIndex) {
|
||||||
|
val reference = getReference<MethodReference>()
|
||||||
|
reference?.name == "getString"
|
||||||
|
}
|
||||||
|
val register = getInstruction<OneRegisterInstruction>(getStringIndex + 1).registerA
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
getStringIndex + 2,
|
||||||
|
"""
|
||||||
|
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getOfflineNetworkErrorString(Ljava/lang/String;)Ljava/lang/String;
|
||||||
|
move-result-object v$register
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.gms
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
import app.revanced.util.containsLiteralInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
internal val specificNetworkErrorViewControllerFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||||
|
returns("V")
|
||||||
|
parameters()
|
||||||
|
custom { method, _ ->
|
||||||
|
method.containsLiteralInstruction(ic_offline_no_content_upside_down)
|
||||||
|
&& method.containsLiteralInstruction(offline_no_content_body_text_not_offline_eligible)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's not clear if this second class is ever used and it may be dead code,
|
||||||
|
// but it the layout image/text is identical to the network error fingerprint above.
|
||||||
|
internal val loadingFrameLayoutControllerFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||||
|
returns("V")
|
||||||
|
parameters("L")
|
||||||
|
custom { method, _ ->
|
||||||
|
method.containsLiteralInstruction(ic_offline_no_content_upside_down)
|
||||||
|
&& method.containsLiteralInstruction(offline_no_content_body_text_not_offline_eligible)
|
||||||
|
}
|
||||||
|
}
|
@ -68,5 +68,5 @@ private fun gmsCoreSupportResourcePatch(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
dependsOn(settingsPatch, addResourcesPatch)
|
dependsOn(settingsPatch, addResourcesPatch, accountCredentialsInvalidTextPatch)
|
||||||
}
|
}
|
||||||
|
@ -524,6 +524,9 @@ Ekranın sağ tərəfində düzünə sürüşdürərək səs səviyyəsini tənz
|
|||||||
<string name="revanced_hide_thanks_button_summary_off">Təşəkkür düyməsi göstərilir</string>
|
<string name="revanced_hide_thanks_button_summary_off">Təşəkkür düyməsi göstərilir</string>
|
||||||
<!-- 'Ask' should be translated with the same localized wording that YouTube displays.
|
<!-- 'Ask' should be translated with the same localized wording that YouTube displays.
|
||||||
Button only shows if the user ip is from specific region such as the USA or EU. -->
|
Button only shows if the user ip is from specific region such as the USA or EU. -->
|
||||||
|
<string name="revanced_hide_ask_button_title">Soruş\'u Gizlət</string>
|
||||||
|
<string name="revanced_hide_ask_button_summary_on">Soruş düyməsi gizlidir</string>
|
||||||
|
<string name="revanced_hide_ask_button_summary_off">\"Soruş\" düyməsi göstərilir</string>
|
||||||
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
|
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
|
||||||
<string name="revanced_hide_clip_button_title">Kəsmə/ gizlət</string>
|
<string name="revanced_hide_clip_button_title">Kəsmə/ gizlət</string>
|
||||||
<string name="revanced_hide_clip_button_summary_on">Kəsmə düyməsi gizlidir</string>
|
<string name="revanced_hide_clip_button_summary_on">Kəsmə düyməsi gizlidir</string>
|
||||||
@ -1252,7 +1255,7 @@ Bunu aktivləşdirmə, bəzi regionlarda əngəllənib silinən şəkilləri dü
|
|||||||
<string name="revanced_alt_thumbnail_options_entry_2">DeArrow & Orijinal miniatürlər</string>
|
<string name="revanced_alt_thumbnail_options_entry_2">DeArrow & Orijinal miniatürlər</string>
|
||||||
<string name="revanced_alt_thumbnail_options_entry_3">DeArrow & Kadr çəkilişlər</string>
|
<string name="revanced_alt_thumbnail_options_entry_3">DeArrow & Kadr çəkilişlər</string>
|
||||||
<string name="revanced_alt_thumbnail_options_entry_4">Kadr çəkilişləri</string>
|
<string name="revanced_alt_thumbnail_options_entry_4">Kadr çəkilişləri</string>
|
||||||
<string name="revanced_alt_thumbnail_dearrow_about_summary">"DeArrow YouTube videoları üçün izdiham mənbəli miniatürlər təqdim edir. Bu miniatürlər YouTube tərəfindən təqdim edilənlərdən dəfələrlə daha uyğundur.
|
<string name="revanced_alt_thumbnail_dearrow_about_summary">"DeArrow YouTube videoları üçün çox mənbəli miniatürlər təqdim edir. Bu miniatürlər YouTube tərəfindən təqdim edilənlərdən dəfələrlə daha uyğundur.
|
||||||
|
|
||||||
Aktivləşdirilərsə, video URL-lər API alıcısına göndəriləcək və başqa məlumat göndərilməyəcək. Videonun DeArrow miniatürləri yoxdursa, orijinal və ya hələ də çəkilişlər göstərilir.
|
Aktivləşdirilərsə, video URL-lər API alıcısına göndəriləcək və başqa məlumat göndərilməyəcək. Videonun DeArrow miniatürləri yoxdursa, orijinal və ya hələ də çəkilişlər göstərilir.
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ Second \"item\" text"</string>
|
|||||||
<string name="revanced_check_environment_manager_not_expected_installer">ReVanced Manager によってインストールされていない</string>
|
<string name="revanced_check_environment_manager_not_expected_installer">ReVanced Manager によってインストールされていない</string>
|
||||||
<string name="revanced_check_environment_not_near_patch_time">10 分以上前にパッチが適用されている</string>
|
<string name="revanced_check_environment_not_near_patch_time">10 分以上前にパッチが適用されている</string>
|
||||||
<string name="revanced_check_environment_not_near_patch_time_days">%s 日前にパッチが適用されている</string>
|
<string name="revanced_check_environment_not_near_patch_time_days">%s 日前にパッチが適用されている</string>
|
||||||
<string name="revanced_check_environment_not_near_patch_time_invalid">APK の作成日情報が破損している</string>
|
<string name="revanced_check_environment_not_near_patch_time_invalid">APK の作成日時データが破損している</string>
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="misc.settings.settingsResourcePatch">
|
<patch id="misc.settings.settingsResourcePatch">
|
||||||
<string name="revanced_settings_submenu_title">設定</string>
|
<string name="revanced_settings_submenu_title">設定</string>
|
||||||
@ -895,10 +895,10 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ
|
|||||||
<string name="revanced_restore_old_seekbar_thumbnails_summary_off">シーク中のサムネイルはプレーヤー画面全体に表示されます</string>
|
<string name="revanced_restore_old_seekbar_thumbnails_summary_off">シーク中のサムネイルはプレーヤー画面全体に表示されます</string>
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="layout.sponsorblock.sponsorBlockResourcePatch">
|
<patch id="layout.sponsorblock.sponsorBlockResourcePatch">
|
||||||
<string name="revanced_sb_enable_sb">SponsorBlock を有効化</string>
|
<string name="revanced_sb_enable_sb">SponsorBlock を有効にする</string>
|
||||||
<string name="revanced_sb_enable_sb_sum">SponsorBlock はユーザーからの情報提供により YouTube 動画のわずらわしい部分をスキップする機能です</string>
|
<string name="revanced_sb_enable_sb_sum">SponsorBlock はユーザーからの情報提供により YouTube 動画のわずらわしい部分をスキップする機能です</string>
|
||||||
<string name="revanced_sb_appearance_category">外観</string>
|
<string name="revanced_sb_appearance_category">外観</string>
|
||||||
<string name="revanced_sb_enable_voting">投票ボタンを表示</string>
|
<string name="revanced_sb_enable_voting">投票ボタンを表示する</string>
|
||||||
<string name="revanced_sb_enable_voting_sum_on">セグメントへの投票ボタンはプレーヤー オーバーレイに表示されます</string>
|
<string name="revanced_sb_enable_voting_sum_on">セグメントへの投票ボタンはプレーヤー オーバーレイに表示されます</string>
|
||||||
<string name="revanced_sb_enable_voting_sum_off">セグメントへの投票ボタンはプレーヤー オーバーレイに表示されません</string>
|
<string name="revanced_sb_enable_voting_sum_off">セグメントへの投票ボタンはプレーヤー オーバーレイに表示されません</string>
|
||||||
<string name="revanced_sb_square_layout">四角ボタンを使用する</string>
|
<string name="revanced_sb_square_layout">四角ボタンを使用する</string>
|
||||||
@ -909,45 +909,45 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ
|
|||||||
<string name="revanced_sb_enable_compact_skip_button_sum_on">ボタンに「スキップ」とだけ表示されます</string>
|
<string name="revanced_sb_enable_compact_skip_button_sum_on">ボタンに「スキップ」とだけ表示されます</string>
|
||||||
<string name="revanced_sb_enable_compact_skip_button_sum_off">ボタンにカテゴリー名が表示されます</string>
|
<string name="revanced_sb_enable_compact_skip_button_sum_off">ボタンにカテゴリー名が表示されます</string>
|
||||||
<string name="revanced_sb_enable_auto_hide_skip_segment_button">スキップボタンを自動的に非表示にする</string>
|
<string name="revanced_sb_enable_auto_hide_skip_segment_button">スキップボタンを自動的に非表示にする</string>
|
||||||
<string name="revanced_sb_enable_auto_hide_skip_segment_button_sum_on">スキップボタンは表示された数秒後に自動的に非表示になります</string>
|
<string name="revanced_sb_enable_auto_hide_skip_segment_button_sum_on">スキップボタンは、表示された数秒後に自動的に非表示になります</string>
|
||||||
<string name="revanced_sb_enable_auto_hide_skip_segment_button_sum_off">スキップボタンはセグメントの開始から終了まで表示されます</string>
|
<string name="revanced_sb_enable_auto_hide_skip_segment_button_sum_off">スキップボタンは、セグメントの開始から終了まで表示されます</string>
|
||||||
<string name="revanced_sb_general_skiptoast">スキップ時にトーストを表示</string>
|
<string name="revanced_sb_general_skiptoast">スキップ時にトーストを表示する</string>
|
||||||
<string name="revanced_sb_general_skiptoast_sum_on">セグメントが自動的にスキップされたときにトースト ポップアップが表示されます。ここをタップするとサンプルが表示されます</string>
|
<string name="revanced_sb_general_skiptoast_sum_on">セグメントが自動的にスキップされたときに、トースト ポップアップが表示されます。ここをタップするとサンプルが表示されます</string>
|
||||||
<string name="revanced_sb_general_skiptoast_sum_off">トースト ポップアップは表示されません。ここをタップするとサンプルが表示されます</string>
|
<string name="revanced_sb_general_skiptoast_sum_off">トースト ポップアップは表示されません。ここをタップするとサンプルが表示されます</string>
|
||||||
<string name="revanced_sb_general_time_without">セグメントを除いた再生時間を表示</string>
|
<string name="revanced_sb_general_time_without">セグメントを除いた再生時間を表示する</string>
|
||||||
<string name="revanced_sb_general_time_without_sum_on">セグメントを除いた再生時間が、動画全体の再生時間の横に括弧付きで表示されます</string>
|
<string name="revanced_sb_general_time_without_sum_on">セグメントを除いた再生時間が、動画全体の再生時間の横に括弧付きで表示されます</string>
|
||||||
<string name="revanced_sb_general_time_without_sum_off">動画全体の再生時間のみが表示されます</string>
|
<string name="revanced_sb_general_time_without_sum_off">動画全体の再生時間のみが表示されます</string>
|
||||||
<string name="revanced_sb_create_segment_category">セグメントの作成</string>
|
<string name="revanced_sb_create_segment_category">セグメントの作成</string>
|
||||||
<string name="revanced_sb_enable_create_segment">セグメント作成ボタンを表示する</string>
|
<string name="revanced_sb_enable_create_segment">セグメント作成ボタンを表示する</string>
|
||||||
<string name="revanced_sb_enable_create_segment_sum_on">セグメント作成ボタンは表示されます</string>
|
<string name="revanced_sb_enable_create_segment_sum_on">セグメント作成ボタンは表示されます</string>
|
||||||
<string name="revanced_sb_enable_create_segment_sum_off">セグメント作成ボタンは表示されません</string>
|
<string name="revanced_sb_enable_create_segment_sum_off">セグメント作成ボタンは表示されません</string>
|
||||||
<string name="revanced_sb_general_adjusting">新しいセグメントステップを調整する</string>
|
<string name="revanced_sb_general_adjusting">セグメントの時間調整幅</string>
|
||||||
<string name="revanced_sb_general_adjusting_sum">新しいセグメントを作成する際の時間調節ボタンの移動時間 (単位: ミリ秒)</string>
|
<string name="revanced_sb_general_adjusting_sum">「セグメントを作成」メニュー内の早送り / 巻き戻しボタンで移動する時間 (ミリ秒)</string>
|
||||||
<string name="revanced_sb_general_adjusting_invalid">値は正の整数でなければなりません</string>
|
<string name="revanced_sb_general_adjusting_invalid">値は正の整数でなければなりません</string>
|
||||||
<string name="revanced_sb_guidelines_preference_title">ガイドラインを見る</string>
|
<string name="revanced_sb_guidelines_preference_title">ガイドラインを見る</string>
|
||||||
<string name="revanced_sb_guidelines_preference_sum">ガイドラインには、新しいセグメントを作成するためのルールとヒントが含まれています</string>
|
<string name="revanced_sb_guidelines_preference_sum">ガイドラインには、新しいセグメントを作成するためのルールとヒントが含まれています</string>
|
||||||
<string name="revanced_sb_guidelines_popup_title">ガイドラインに従ってください</string>
|
<string name="revanced_sb_guidelines_popup_title">ガイドラインに従ってください</string>
|
||||||
<string name="revanced_sb_guidelines_popup_content">新しいセグメントを作成する前に SponsorBlock ガイドラインを読んでください</string>
|
<string name="revanced_sb_guidelines_popup_content">新しいセグメントを作成する前に SponsorBlock ガイドラインを読んでください</string>
|
||||||
<string name="revanced_sb_guidelines_popup_already_read">既に読んでいます</string>
|
<string name="revanced_sb_guidelines_popup_already_read">既読</string>
|
||||||
<string name="revanced_sb_guidelines_popup_open">見る</string>
|
<string name="revanced_sb_guidelines_popup_open">表示</string>
|
||||||
<string name="revanced_sb_general">一般設定</string>
|
<string name="revanced_sb_general">その他</string>
|
||||||
<string name="revanced_sb_toast_on_connection_error_title">API 利用不可時にトーストを表示</string>
|
<string name="revanced_sb_toast_on_connection_error_title">API 利用不可時にトーストを表示する</string>
|
||||||
<string name="revanced_sb_toast_on_connection_error_summary_on">SponsorBlock が利用できない場合はトースト ポップアップが表示されます</string>
|
<string name="revanced_sb_toast_on_connection_error_summary_on">SponsorBlock が利用できない場合は、トースト ポップアップが表示されます</string>
|
||||||
<string name="revanced_sb_toast_on_connection_error_summary_off">SponsorBlock が利用できない場合でもトースト ポップアップは表示されません</string>
|
<string name="revanced_sb_toast_on_connection_error_summary_off">SponsorBlock が利用できない場合でも、トースト ポップアップは表示されません</string>
|
||||||
<string name="revanced_sb_general_skipcount">スキップ数の追跡を有効にする</string>
|
<string name="revanced_sb_general_skipcount">スキップデータを送信する</string>
|
||||||
<string name="revanced_sb_general_skipcount_sum_on">SponsorBlock リーダーボードに、どれだけの時間が節約されたかを報告します。セグメントがスキップされるたびにメッセージがリーダーボードに送信されます</string>
|
<string name="revanced_sb_general_skipcount_sum_on">SponsorBlock リーダーボード にスキップによって節約した時間を送信します。セグメントをスキップする度にデータを送信します</string>
|
||||||
<string name="revanced_sb_general_skipcount_sum_off">スキップカウント追跡が有効になっていません</string>
|
<string name="revanced_sb_general_skipcount_sum_off">スキップデータは送信されません</string>
|
||||||
<string name="revanced_sb_general_min_duration">最小のセグメントの長さ</string>
|
<string name="revanced_sb_general_min_duration">セグメントのしきい値</string>
|
||||||
<string name="revanced_sb_general_min_duration_sum">設定値 (単位: 秒) より短いセグメントはスキップされず、プレーヤーにも表示されません</string>
|
<string name="revanced_sb_general_min_duration_sum">設定値 (単位: 秒) より短いセグメントはスキップされず、プレーヤーにも表示されません</string>
|
||||||
<string name="revanced_sb_general_min_duration_invalid">セグメントのしきい値が無効です</string>
|
<string name="revanced_sb_general_min_duration_invalid">セグメントのしきい値が無効です</string>
|
||||||
<string name="revanced_sb_general_uuid">非公開ユーザー ID</string>
|
<string name="revanced_sb_general_uuid">非公開ユーザー ID</string>
|
||||||
<string name="revanced_sb_general_uuid_sum">この ID は公開すべきではありません。パスワードのようなものであり、誰とも共有すべきではありません。もし誰かがこの ID を手に入れた場合、あなたになりすますことができます</string>
|
<string name="revanced_sb_general_uuid_sum">この ID は公開すべきではありません。パスワードのようなものであり、誰とも共有すべきではありません。もし誰かがこの ID を手に入れた場合、あなたになりすますことができます</string>
|
||||||
<string name="revanced_sb_general_uuid_invalid">非公開ユーザー ID は 30 文字以上必要です</string>
|
<string name="revanced_sb_general_uuid_invalid">非公開ユーザー ID は 30 文字以上必要です</string>
|
||||||
<string name="revanced_sb_general_api_url">API の URL を変更</string>
|
<string name="revanced_sb_general_api_url">API URL</string>
|
||||||
<string name="revanced_sb_general_api_url_sum">SponsorBlockのアドレスはサーバーへの呼び出しに使用されます</string>
|
<string name="revanced_sb_general_api_url_sum">SponsorBlock がサーバーとの通信で使用するアドレス</string>
|
||||||
<string name="revanced_sb_api_url_reset">API の URL をリセットしました</string>
|
<string name="revanced_sb_api_url_reset">API URL をリセットしました</string>
|
||||||
<string name="revanced_sb_api_url_invalid">API URL が無効です</string>
|
<string name="revanced_sb_api_url_invalid">API URL が無効です</string>
|
||||||
<string name="revanced_sb_api_url_changed">API の URL を変更しました</string>
|
<string name="revanced_sb_api_url_changed">API URL を変更しました</string>
|
||||||
<string name="revanced_sb_settings_ie">設定のインポート / エクスポート</string>
|
<string name="revanced_sb_settings_ie">設定のインポート / エクスポート</string>
|
||||||
<string name="revanced_sb_settings_copy">コピー</string>
|
<string name="revanced_sb_settings_copy">コピー</string>
|
||||||
<string name="revanced_sb_settings_ie_sum">SponsorBlock の設定を JSON 形式のテキストでインポート / エクスポートします。この JSON テキストは他のプラットフォームでも利用可能です</string>
|
<string name="revanced_sb_settings_ie_sum">SponsorBlock の設定を JSON 形式のテキストでインポート / エクスポートします。この JSON テキストは他のプラットフォームでも利用可能です</string>
|
||||||
@ -955,7 +955,7 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ
|
|||||||
<string name="revanced_sb_settings_import_successful">設定が正常にインポートされました</string>
|
<string name="revanced_sb_settings_import_successful">設定が正常にインポートされました</string>
|
||||||
<string name="revanced_sb_settings_import_failed">インポートに失敗しました: %s</string>
|
<string name="revanced_sb_settings_import_failed">インポートに失敗しました: %s</string>
|
||||||
<string name="revanced_sb_settings_export_failed">エクスポートに失敗しました: %s</string>
|
<string name="revanced_sb_settings_export_failed">エクスポートに失敗しました: %s</string>
|
||||||
<string name="revanced_sb_settings_revanced_export_user_id_warning">"設定には、SponsorBlock の非公開ユーザー ID が含まれています。このユーザー ID はパスワードのようなものであり、決して共有すべきではありません。"</string>
|
<string name="revanced_sb_settings_revanced_export_user_id_warning">"設定には、SponsorBlock の非公開ユーザー ID が含まれています。この ID はパスワードのようなものであり、決して共有すべきではありません。"</string>
|
||||||
<string name="revanced_sb_settings_revanced_export_user_id_warning_dismiss">今後表示しない</string>
|
<string name="revanced_sb_settings_revanced_export_user_id_warning_dismiss">今後表示しない</string>
|
||||||
<string name="revanced_sb_diff_segments">セグメントのスキップ</string>
|
<string name="revanced_sb_diff_segments">セグメントのスキップ</string>
|
||||||
<string name="revanced_sb_segments_sponsor">スポンサー</string>
|
<string name="revanced_sb_segments_sponsor">スポンサー</string>
|
||||||
@ -968,7 +968,7 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ
|
|||||||
<string name="revanced_sb_segments_highlight_sum">動画の中で最も興味を引く場面</string>
|
<string name="revanced_sb_segments_highlight_sum">動画の中で最も興味を引く場面</string>
|
||||||
<string name="revanced_sb_segments_intro">幕間 / オープニング (イントロ)</string>
|
<string name="revanced_sb_segments_intro">幕間 / オープニング (イントロ)</string>
|
||||||
<string name="revanced_sb_segments_intro_sum">実際のコンテンツを含まない間隔。一時停止、固定フレーム、繰り返しアニメーションを使用できます。情報を含むトランジションは含まれません。</string>
|
<string name="revanced_sb_segments_intro_sum">実際のコンテンツを含まない間隔。一時停止、固定フレーム、繰り返しアニメーションを使用できます。情報を含むトランジションは含まれません。</string>
|
||||||
<string name="revanced_sb_segments_outro">終了画面 / クレジット (アウトロ)</string>
|
<string name="revanced_sb_segments_outro">終了画面 / クレジット(アウトロ)</string>
|
||||||
<string name="revanced_sb_segments_outro_sum">クレジットまたはYouTubeのエンドカードが表示される場合、情報を持つ結論にはなりません</string>
|
<string name="revanced_sb_segments_outro_sum">クレジットまたはYouTubeのエンドカードが表示される場合、情報を持つ結論にはなりません</string>
|
||||||
<string name="revanced_sb_segments_preview">予告編 / 総集編 / フック</string>
|
<string name="revanced_sb_segments_preview">予告編 / 総集編 / フック</string>
|
||||||
<string name="revanced_sb_segments_preview_sum">ビデオやシリーズの他のビデオで何が起こったのかを示すクリップのコレクション 全ての情報が他の場所で繰り返されます</string>
|
<string name="revanced_sb_segments_preview_sum">ビデオやシリーズの他のビデオで何が起こったのかを示すクリップのコレクション 全ての情報が他の場所で繰り返されます</string>
|
||||||
@ -1024,9 +1024,9 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ
|
|||||||
<string name="revanced_sb_sponsorblock_connection_failure_timeout">SponsorBlock は一時的に利用できません (API タイムアウト)</string>
|
<string name="revanced_sb_sponsorblock_connection_failure_timeout">SponsorBlock は一時的に利用できません (API タイムアウト)</string>
|
||||||
<string name="revanced_sb_sponsorblock_connection_failure_status">SponsorBlockは一時的に利用できません (ステータス: %d)</string>
|
<string name="revanced_sb_sponsorblock_connection_failure_status">SponsorBlockは一時的に利用できません (ステータス: %d)</string>
|
||||||
<string name="revanced_sb_sponsorblock_connection_failure_generic">SponsorBlockは一時的に利用できません</string>
|
<string name="revanced_sb_sponsorblock_connection_failure_generic">SponsorBlockは一時的に利用できません</string>
|
||||||
<string name="revanced_sb_vote_failed_timeout">セグメントに投票できません (API タイムアウト)</string>
|
<string name="revanced_sb_vote_failed_timeout">セグメントに投票できませんでした (API タイムアウト)</string>
|
||||||
<string name="revanced_sb_vote_failed_unknown_error">セグメントに投票できませんでした(ステータス: %1$d %2$s)</string>
|
<string name="revanced_sb_vote_failed_unknown_error">セグメントに投票できませんでした(ステータス: %1$d %2$s)</string>
|
||||||
<string name="revanced_sb_vote_failed_forbidden">セグメントに投票できません: %s</string>
|
<string name="revanced_sb_vote_failed_forbidden">セグメントに投票できませんでした: %s</string>
|
||||||
<string name="revanced_sb_vote_upvote">高評価</string>
|
<string name="revanced_sb_vote_upvote">高評価</string>
|
||||||
<string name="revanced_sb_vote_downvote">低評価</string>
|
<string name="revanced_sb_vote_downvote">低評価</string>
|
||||||
<string name="revanced_sb_vote_category">カテゴリーの変更</string>
|
<string name="revanced_sb_vote_category">カテゴリーの変更</string>
|
||||||
@ -1083,7 +1083,7 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ
|
|||||||
<string name="revanced_sb_color_opacity_label">透明度:</string>
|
<string name="revanced_sb_color_opacity_label">透明度:</string>
|
||||||
<string name="revanced_sb_color_dot_label">色:</string>
|
<string name="revanced_sb_color_dot_label">色:</string>
|
||||||
<string name="revanced_sb_color_changed">色を変更しました</string>
|
<string name="revanced_sb_color_changed">色を変更しました</string>
|
||||||
<string name="revanced_sb_color_reset">色をリセット</string>
|
<string name="revanced_sb_color_reset">色がリセットされました</string>
|
||||||
<string name="revanced_sb_color_invalid">色の値が無効です</string>
|
<string name="revanced_sb_color_invalid">色の値が無効です</string>
|
||||||
<string name="revanced_sb_reset_color">色をリセット</string>
|
<string name="revanced_sb_reset_color">色をリセット</string>
|
||||||
<string name="revanced_sb_reset">リセット</string>
|
<string name="revanced_sb_reset">リセット</string>
|
||||||
|
@ -524,7 +524,7 @@ Podesite jačinu zvuka prevlačenjem vertikalno na desnoj strani ekrana"</string
|
|||||||
<string name="revanced_hide_thanks_button_summary_off">Dugme „Hvala” je prikazano</string>
|
<string name="revanced_hide_thanks_button_summary_off">Dugme „Hvala” je prikazano</string>
|
||||||
<!-- 'Ask' should be translated with the same localized wording that YouTube displays.
|
<!-- 'Ask' should be translated with the same localized wording that YouTube displays.
|
||||||
Button only shows if the user ip is from specific region such as the USA or EU. -->
|
Button only shows if the user ip is from specific region such as the USA or EU. -->
|
||||||
<string name="revanced_hide_ask_button_title">Sakrij „Pitaj”</string>
|
<string name="revanced_hide_ask_button_title">Sakrij dugme „Pitaj”</string>
|
||||||
<string name="revanced_hide_ask_button_summary_on">Dugme „Pitaj” je skriveno</string>
|
<string name="revanced_hide_ask_button_summary_on">Dugme „Pitaj” je skriveno</string>
|
||||||
<string name="revanced_hide_ask_button_summary_off">Dugme „Pitaj” je prikazano</string>
|
<string name="revanced_hide_ask_button_summary_off">Dugme „Pitaj” je prikazano</string>
|
||||||
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
|
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
|
||||||
|
@ -524,7 +524,7 @@ Second \"item\" text"</string>
|
|||||||
<string name="revanced_hide_thanks_button_summary_off">Дугме „Хвала” је приказано</string>
|
<string name="revanced_hide_thanks_button_summary_off">Дугме „Хвала” је приказано</string>
|
||||||
<!-- 'Ask' should be translated with the same localized wording that YouTube displays.
|
<!-- 'Ask' should be translated with the same localized wording that YouTube displays.
|
||||||
Button only shows if the user ip is from specific region such as the USA or EU. -->
|
Button only shows if the user ip is from specific region such as the USA or EU. -->
|
||||||
<string name="revanced_hide_ask_button_title">Сакриј „Питај”</string>
|
<string name="revanced_hide_ask_button_title">Сакриј дугме „Питај”</string>
|
||||||
<string name="revanced_hide_ask_button_summary_on">Дугме „Питај” је скривено</string>
|
<string name="revanced_hide_ask_button_summary_on">Дугме „Питај” је скривено</string>
|
||||||
<string name="revanced_hide_ask_button_summary_off">Дугме „Питај” је приказано</string>
|
<string name="revanced_hide_ask_button_summary_off">Дугме „Питај” је приказано</string>
|
||||||
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
|
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
|
||||||
|
@ -1379,6 +1379,9 @@ Enabling this can unlock higher video qualities"</string>
|
|||||||
<string name="microg_settings_title">GmsCore Settings</string>
|
<string name="microg_settings_title">GmsCore Settings</string>
|
||||||
<string name="microg_settings_summary">Settings for GmsCore</string>
|
<string name="microg_settings_summary">Settings for GmsCore</string>
|
||||||
</patch>
|
</patch>
|
||||||
|
<patch id="misc.gms.accountCredentialsInvalidTextPatch">
|
||||||
|
<string name="microg_offline_account_login_error">If you recently changed your account login details, then uninstall and reinstall MicroG.</string>
|
||||||
|
</patch>
|
||||||
<patch id="misc.links.bypassURLRedirectsPatch">
|
<patch id="misc.links.bypassURLRedirectsPatch">
|
||||||
<string name="revanced_bypass_url_redirects_title">Bypass URL redirects</string>
|
<string name="revanced_bypass_url_redirects_title">Bypass URL redirects</string>
|
||||||
<string name="revanced_bypass_url_redirects_summary_on">URL redirects are bypassed</string>
|
<string name="revanced_bypass_url_redirects_summary_on">URL redirects are bypassed</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user