Compare commits

...

9 Commits

Author SHA1 Message Date
semantic-release-bot
903cdb9bb3 chore: Release v5.22.0-dev.3 [skip ci]
# [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](ab4bdc8a25))
2025-04-29 09:40:18 +00:00
LisoUseInAIKyrios
ab4bdc8a25
feat(YouTube - GmsCore support): Show troubleshooting in app text if the user recently changed their account details (#4879) 2025-04-29 13:36:29 +04:00
semantic-release-bot
1d5c6c9351 chore: Release v5.22.0-dev.2 [skip ci]
# [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](06b35b2a7d))
2025-04-27 14:28:33 +00:00
LisoUseInAIKyrios
06b35b2a7d fix(YouTube - Shorts autoplay): Fix autoplay with YT 20.12 2025-04-27 18:24:37 +04:00
semantic-release-bot
a1207c9784 chore: Release v5.22.0-dev.1 [skip ci]
# [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](c255ac18e0))
* **YouTube - Spoof app version:** Do not hide spoof version in general settings menu ([#4861](https://github.com/ReVanced/revanced-patches/issues/4861)) ([f459c3c](f459c3c7fa))

### Features

* **TikTok - Feed Filter:** Remove TikTok Shop from feed. ([#4851](https://github.com/ReVanced/revanced-patches/issues/4851)) ([f198bec](f198bece65))
2025-04-26 13:55:47 +00:00
3igcheeze
f198bece65
feat(TikTok - Feed Filter): Remove TikTok Shop from feed. (#4851) 2025-04-26 17:52:17 +04:00
LisoUseInAIKyrios
f459c3c7fa
fix(YouTube - Spoof app version): Do not hide spoof version in general settings menu (#4861) 2025-04-26 17:51:35 +04:00
github-actions[bot]
39769bf384
chore: Sync translations (#4865) 2025-04-26 17:51:18 +04:00
Jaimy Smets
c255ac18e0
fix(TikTok - Feed filter): Hide ads in following feed (#4844) 2025-04-26 17:49:28 +04:00
27 changed files with 465 additions and 98 deletions

View File

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

View File

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

View File

@ -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;
for (IFilter filter : FILTERS) { public static void filter(FollowFeedList followFeedList) {
boolean enabled = filter.getEnabled(); filterFeedList(followFeedList.mItems, feed -> (feed != null) ? feed.aweme : null);
if (enabled && filter.getFiltered(item)) { }
feedItemListIterator.remove();
break; 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) {
if (filter.getEnabled() && filter.getFiltered(item)) {
return true;
}
}
return false;
}
@FunctionalInterface
interface AwemeExtractor<T> {
Aweme extract(T source);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,16 +122,17 @@ 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
""" """
) )
}
} }
} }

View File

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

View File

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

View File

@ -68,5 +68,5 @@ private fun gmsCoreSupportResourcePatch(
) )
}, },
) { ) {
dependsOn(settingsPatch, addResourcesPatch) dependsOn(settingsPatch, addResourcesPatch, accountCredentialsInvalidTextPatch)
} }

View File

@ -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 &amp; Orijinal miniatürlər</string> <string name="revanced_alt_thumbnail_options_entry_2">DeArrow &amp; Orijinal miniatürlər</string>
<string name="revanced_alt_thumbnail_options_entry_3">DeArrow &amp; Kadr çəkilişlər</string> <string name="revanced_alt_thumbnail_options_entry_3">DeArrow &amp; 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.

View File

@ -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>
@ -1009,7 +1009,7 @@ MicroG GmsCore に対する電池の最適化を無効にしても、バッテ
<string name="revanced_sb_skipped_multiple_segments">複数のセグメントをスキップしました</string> <string name="revanced_sb_skipped_multiple_segments">複数のセグメントをスキップしました</string>
<string name="revanced_sb_skip_automatically">自動的にスキップ</string> <string name="revanced_sb_skip_automatically">自動的にスキップ</string>
<string name="revanced_sb_skip_automatically_once">1 回だけ自動的にスキップ</string> <string name="revanced_sb_skip_automatically_once">1 回だけ自動的にスキップ</string>
<string name="revanced_sb_skip_showbutton">スキップ ボタンを表示</string> <string name="revanced_sb_skip_showbutton">スキップボタンを表示</string>
<string name="revanced_sb_skip_seekbaronly">シークバーに表示</string> <string name="revanced_sb_skip_seekbaronly">シークバーに表示</string>
<string name="revanced_sb_skip_ignore">無効</string> <string name="revanced_sb_skip_ignore">無効</string>
<string name="revanced_sb_submit_failed_invalid">セグメント送信失敗: %s</string> <string name="revanced_sb_submit_failed_invalid">セグメント送信失敗: %s</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>

View File

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

View File

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

View File

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