mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-04-29 22:24:31 +02:00
fix(YouTube - Shorts components): Autoplay
option of Change Shorts repeat state
not working (20.09+)
This commit is contained in:
parent
fec13ad15b
commit
c85816bbe9
@ -2,6 +2,8 @@ package app.revanced.extension.youtube.patches.shorts;
|
|||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@ -28,11 +30,16 @@ public class ShortsRepeatStatePatch {
|
|||||||
END_SCREEN;
|
END_SCREEN;
|
||||||
|
|
||||||
static void setYTEnumValue(Enum<?> ytBehavior) {
|
static void setYTEnumValue(Enum<?> ytBehavior) {
|
||||||
|
String ytName = ytBehavior.name();
|
||||||
for (ShortsLoopBehavior rvBehavior : values()) {
|
for (ShortsLoopBehavior rvBehavior : values()) {
|
||||||
if (ytBehavior.name().endsWith(rvBehavior.name())) {
|
if (ytName.endsWith(rvBehavior.name())) {
|
||||||
rvBehavior.ytEnumValue = ytBehavior;
|
if (rvBehavior.ytEnumValue != null) {
|
||||||
|
Logger.printException(() -> "Conflicting behavior names: " + rvBehavior
|
||||||
Logger.printDebug(() -> rvBehavior + " set to YT enum: " + ytBehavior.name());
|
+ " ytBehavior: " + ytName);
|
||||||
|
} else {
|
||||||
|
rvBehavior.ytEnumValue = ytBehavior;
|
||||||
|
Logger.printDebug(() -> rvBehavior + " set to YT enum: " + ytName);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,25 +84,39 @@ public class ShortsRepeatStatePatch {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static Enum<?> changeShortsRepeatBehavior(Enum<?> original) {
|
@Nullable
|
||||||
|
public static Enum<?> changeShortsRepeatBehavior(@Nullable Enum<?> original) {
|
||||||
try {
|
try {
|
||||||
final ShortsLoopBehavior behavior = ExtendedUtils.IS_19_34_OR_GREATER &&
|
if (original == null) {
|
||||||
|
Logger.printDebug(() -> "Original is null, returning null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortsLoopBehavior behavior = ExtendedUtils.IS_19_34_OR_GREATER &&
|
||||||
isAppInBackgroundPiPMode()
|
isAppInBackgroundPiPMode()
|
||||||
? Settings.CHANGE_SHORTS_BACKGROUND_REPEAT_STATE.get()
|
? Settings.CHANGE_SHORTS_BACKGROUND_REPEAT_STATE.get()
|
||||||
: Settings.CHANGE_SHORTS_REPEAT_STATE.get();
|
: Settings.CHANGE_SHORTS_REPEAT_STATE.get();
|
||||||
|
Enum<?> overrideBehavior = behavior.ytEnumValue;
|
||||||
|
|
||||||
if (behavior != ShortsLoopBehavior.UNKNOWN && behavior.ytEnumValue != null) {
|
if (overrideBehavior != null) {
|
||||||
Logger.printDebug(() -> behavior.ytEnumValue == original
|
Logger.printDebug(() -> overrideBehavior == original
|
||||||
? "Changing Shorts repeat behavior from: " + original.name() + " to: " + behavior.ytEnumValue
|
? "Behavior setting is same as original. Using original: " + original.name()
|
||||||
: "Behavior setting is same as original. Using original: " + original.name()
|
: "Changing Shorts repeat behavior from: " + original.name() + " to: " + overrideBehavior.name()
|
||||||
);
|
);
|
||||||
|
|
||||||
return behavior.ytEnumValue;
|
return overrideBehavior;
|
||||||
}
|
}
|
||||||
} 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(@Nullable Enum<?> original) {
|
||||||
|
return original != null && ShortsLoopBehavior.SINGLE_PLAY.ytEnumValue == original;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import app.revanced.util.or
|
|||||||
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.Method
|
||||||
|
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 kotlin.collections.listOf
|
import kotlin.collections.listOf
|
||||||
|
|
||||||
@ -71,6 +72,41 @@ internal val reelEnumStaticFingerprint = legacyFingerprint(
|
|||||||
returnType = "L"
|
returnType = "L"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* YouTube 18.49.36 ~
|
||||||
|
*/
|
||||||
|
internal val reelPlaybackRepeatFingerprint = legacyFingerprint(
|
||||||
|
name = "reelPlaybackRepeatFingerprint",
|
||||||
|
returnType = "V",
|
||||||
|
parameters = listOf("L"),
|
||||||
|
strings = listOf("YoutubePlayerState is in throwing an Error.")
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val reelPlaybackFingerprint = legacyFingerprint(
|
||||||
|
name = "reelPlaybackFingerprint",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("J"),
|
||||||
|
returnType = "V",
|
||||||
|
customFingerprint = { 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"
|
||||||
|
}
|
||||||
|
|
||||||
internal const val SHORTS_HUD_FEATURE_FLAG = 45644023L
|
internal const val SHORTS_HUD_FEATURE_FLAG = 45644023L
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,10 +33,12 @@ import app.revanced.patches.youtube.utils.patch.PatchList.SHORTS_COMPONENTS
|
|||||||
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
|
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_18_31_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_18_31_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_18_34_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_18_34_or_greater
|
||||||
|
import app.revanced.patches.youtube.utils.playservice.is_18_49_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_02_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_02_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_28_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_28_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater
|
||||||
|
import app.revanced.patches.youtube.utils.playservice.is_20_09_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||||
import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverHook
|
import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverHook
|
||||||
import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverPatch
|
import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverPatch
|
||||||
@ -60,6 +62,7 @@ import app.revanced.patches.youtube.utils.settings.ResourceUtils.getContext
|
|||||||
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||||
import app.revanced.patches.youtube.utils.toolbar.hookToolBar
|
import app.revanced.patches.youtube.utils.toolbar.hookToolBar
|
||||||
import app.revanced.patches.youtube.utils.toolbar.toolBarHookPatch
|
import app.revanced.patches.youtube.utils.toolbar.toolBarHookPatch
|
||||||
|
import app.revanced.patches.youtube.utils.videoIdFingerprintShorts
|
||||||
import app.revanced.patches.youtube.video.information.hookShortsVideoInformation
|
import app.revanced.patches.youtube.video.information.hookShortsVideoInformation
|
||||||
import app.revanced.patches.youtube.video.information.videoInformationPatch
|
import app.revanced.patches.youtube.video.information.videoInformationPatch
|
||||||
import app.revanced.patches.youtube.video.playbackstart.PLAYBACK_START_DESCRIPTOR_CLASS_DESCRIPTOR
|
import app.revanced.patches.youtube.video.playbackstart.PLAYBACK_START_DESCRIPTOR_CLASS_DESCRIPTOR
|
||||||
@ -71,11 +74,11 @@ import app.revanced.patches.youtube.video.videoid.hookPlayerResponseVideoId
|
|||||||
import app.revanced.patches.youtube.video.videoid.videoIdPatch
|
import app.revanced.patches.youtube.video.videoid.videoIdPatch
|
||||||
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
|
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
|
||||||
import app.revanced.util.ResourceGroup
|
import app.revanced.util.ResourceGroup
|
||||||
|
import app.revanced.util.addEntryValues
|
||||||
import app.revanced.util.cloneMutable
|
import app.revanced.util.cloneMutable
|
||||||
import app.revanced.util.copyResources
|
import app.revanced.util.copyResources
|
||||||
import app.revanced.util.findMethodOrThrow
|
import app.revanced.util.findMethodOrThrow
|
||||||
import app.revanced.util.findMutableMethodOf
|
import app.revanced.util.findMutableMethodOf
|
||||||
import app.revanced.util.fingerprint.definingClassOrThrow
|
|
||||||
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
|
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
|
||||||
import app.revanced.util.fingerprint.matchOrThrow
|
import app.revanced.util.fingerprint.matchOrThrow
|
||||||
import app.revanced.util.fingerprint.methodOrThrow
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
@ -94,6 +97,7 @@ import app.revanced.util.or
|
|||||||
import app.revanced.util.replaceLiteralInstructionCall
|
import app.revanced.util.replaceLiteralInstructionCall
|
||||||
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.instruction.FiveRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
@ -403,9 +407,7 @@ private val shortsRepeatPatch = bytecodePatch(
|
|||||||
"setMainActivity"
|
"setMainActivity"
|
||||||
)
|
)
|
||||||
|
|
||||||
val reelEnumClass = reelEnumConstructorFingerprint.definingClassOrThrow()
|
val endScreenReference = with (reelEnumConstructorFingerprint.methodOrThrow()) {
|
||||||
|
|
||||||
reelEnumConstructorFingerprint.methodOrThrow().apply {
|
|
||||||
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.RETURN_VOID)
|
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.RETURN_VOID)
|
||||||
|
|
||||||
addInstructions(
|
addInstructions(
|
||||||
@ -413,7 +415,7 @@ private val shortsRepeatPatch = bytecodePatch(
|
|||||||
"""
|
"""
|
||||||
# Pass the first enum value to extension.
|
# Pass the first enum value to extension.
|
||||||
# Any enum value of this type will work.
|
# Any enum value of this type will work.
|
||||||
sget-object v0, $reelEnumClass->a:$reelEnumClass
|
sget-object v0, $definingClass->a:$definingClass
|
||||||
invoke-static { v0 }, $EXTENSION_REPEAT_STATE_CLASS_DESCRIPTOR->setYTShortsRepeatEnum(Ljava/lang/Enum;)V
|
invoke-static { v0 }, $EXTENSION_REPEAT_STATE_CLASS_DESCRIPTOR->setYTShortsRepeatEnum(Ljava/lang/Enum;)V
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
@ -422,50 +424,132 @@ private val shortsRepeatPatch = bytecodePatch(
|
|||||||
indexOfFirstStringInstructionOrThrow("REEL_LOOP_BEHAVIOR_END_SCREEN")
|
indexOfFirstStringInstructionOrThrow("REEL_LOOP_BEHAVIOR_END_SCREEN")
|
||||||
val endScreenReferenceIndex =
|
val endScreenReferenceIndex =
|
||||||
indexOfFirstInstructionOrThrow(endScreenStringIndex, Opcode.SPUT_OBJECT)
|
indexOfFirstInstructionOrThrow(endScreenStringIndex, Opcode.SPUT_OBJECT)
|
||||||
val endScreenReference =
|
|
||||||
getInstruction<ReferenceInstruction>(endScreenReferenceIndex).reference.toString()
|
|
||||||
|
|
||||||
val enumMethod = reelEnumStaticFingerprint.methodOrThrow(reelEnumConstructorFingerprint)
|
getInstruction<ReferenceInstruction>(endScreenReferenceIndex).reference.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
lateinit var insertMethod: MutableMethod
|
||||||
|
var insertMethodFound = false
|
||||||
|
|
||||||
|
if (is_18_49_or_greater) {
|
||||||
|
insertMethod = reelPlaybackRepeatFingerprint.methodOrThrow()
|
||||||
|
} else {
|
||||||
|
val isInsertMethod: Method.() -> Boolean = {
|
||||||
|
parameters.size == 1 &&
|
||||||
|
parameterTypes.first().startsWith("L") &&
|
||||||
|
returnType == "V" &&
|
||||||
|
indexOfFirstInstruction {
|
||||||
|
getReference<FieldReference>()?.toString() == endScreenReference
|
||||||
|
} >= 0
|
||||||
|
}
|
||||||
|
|
||||||
classes.forEach { classDef ->
|
classes.forEach { classDef ->
|
||||||
classDef.methods.filter { method ->
|
if (!insertMethodFound) {
|
||||||
method.parameters.size == 1 &&
|
classDef.methods.forEach { method ->
|
||||||
method.parameters[0].startsWith("L") &&
|
if (method.isInsertMethod()) {
|
||||||
method.returnType == "V" &&
|
insertMethodFound = true
|
||||||
method.indexOfFirstInstruction {
|
insertMethod = proxy(classDef)
|
||||||
getReference<FieldReference>()?.toString() == endScreenReference
|
.mutableClass
|
||||||
} >= 0
|
.findMutableMethodOf(method)
|
||||||
}.forEach { targetMethod ->
|
|
||||||
proxy(classDef)
|
|
||||||
.mutableClass
|
|
||||||
.findMutableMethodOf(targetMethod)
|
|
||||||
.apply {
|
|
||||||
implementation!!.instructions
|
|
||||||
.withIndex()
|
|
||||||
.filter { (_, instruction) ->
|
|
||||||
val reference =
|
|
||||||
(instruction as? ReferenceInstruction)?.reference
|
|
||||||
reference is MethodReference &&
|
|
||||||
MethodUtil.methodSignaturesMatch(enumMethod, reference)
|
|
||||||
}
|
|
||||||
.map { (index, _) -> index }
|
|
||||||
.reversed()
|
|
||||||
.forEach { index ->
|
|
||||||
val register =
|
|
||||||
getInstruction<OneRegisterInstruction>(index + 1).registerA
|
|
||||||
|
|
||||||
addInstructions(
|
|
||||||
index + 2, """
|
|
||||||
invoke-static {v$register}, $EXTENSION_REPEAT_STATE_CLASS_DESCRIPTOR->changeShortsRepeatBehavior(Ljava/lang/Enum;)Ljava/lang/Enum;
|
|
||||||
move-result-object v$register
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val enumMethod = reelEnumStaticFingerprint.methodOrThrow(reelEnumConstructorFingerprint)
|
||||||
|
|
||||||
|
insertMethod.apply {
|
||||||
|
implementation!!.instructions
|
||||||
|
.withIndex()
|
||||||
|
.filter { (_, instruction) ->
|
||||||
|
val reference =
|
||||||
|
(instruction as? ReferenceInstruction)?.reference
|
||||||
|
reference is MethodReference &&
|
||||||
|
MethodUtil.methodSignaturesMatch(enumMethod, reference)
|
||||||
|
}
|
||||||
|
.map { (index, _) -> index }
|
||||||
|
.reversed()
|
||||||
|
.forEach { index ->
|
||||||
|
val register =
|
||||||
|
getInstruction<OneRegisterInstruction>(index + 1).registerA
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
index + 2, """
|
||||||
|
invoke-static {v$register}, $EXTENSION_REPEAT_STATE_CLASS_DESCRIPTOR->changeShortsRepeatBehavior(Ljava/lang/Enum;)Ljava/lang/Enum;
|
||||||
|
move-result-object v$register
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// As of YouTube 20.09, Google has removed the code for 'Autoplay' and 'Pause' from this method.
|
||||||
|
// Manually add the 'Autoplay' code that Google removed.
|
||||||
|
// Tested on YouTube 20.10.
|
||||||
|
// TODO: add the 'Pause' code that Google removed.
|
||||||
|
if (is_20_09_or_greater) {
|
||||||
|
val (directReference, virtualReference) = with (reelPlaybackFingerprint.methodOrThrow(videoIdFingerprintShorts)) {
|
||||||
|
val directIndex = indexOfInitializationInstruction(this)
|
||||||
|
val virtualIndex = indexOfFirstInstructionOrThrow(directIndex) {
|
||||||
|
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||||
|
getReference<MethodReference>()?.parameterTypes?.size == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Pair(
|
||||||
|
getInstruction<ReferenceInstruction>(directIndex).reference as MethodReference,
|
||||||
|
getInstruction<ReferenceInstruction>(virtualIndex).reference as MethodReference
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
insertMethod.apply {
|
||||||
|
val extensionIndex = indexOfFirstInstructionOrThrow {
|
||||||
|
opcode == Opcode.INVOKE_STATIC &&
|
||||||
|
getReference<MethodReference>()?.definingClass == EXTENSION_REPEAT_STATE_CLASS_DESCRIPTOR
|
||||||
|
}
|
||||||
|
val enumRegister = getInstruction<OneRegisterInstruction>(extensionIndex + 1).registerA
|
||||||
|
val freeIndex = indexOfFirstInstructionOrThrow(extensionIndex) {
|
||||||
|
opcode == Opcode.SGET_OBJECT &&
|
||||||
|
getReference<FieldReference>()?.name != "a"
|
||||||
|
}
|
||||||
|
val freeRegister = getInstruction<OneRegisterInstruction>(freeIndex).registerA
|
||||||
|
val getIndex = indexOfFirstInstructionOrThrow(extensionIndex) {
|
||||||
|
val reference = getReference<FieldReference>()
|
||||||
|
opcode == Opcode.IGET_OBJECT &&
|
||||||
|
reference?.definingClass == definingClass &&
|
||||||
|
reference.type == virtualReference.definingClass
|
||||||
|
}
|
||||||
|
val getReference = getInstruction<ReferenceInstruction>(getIndex).reference
|
||||||
|
|
||||||
|
addInstructionsWithLabels(
|
||||||
|
extensionIndex + 2, """
|
||||||
|
invoke-static {v$enumRegister}, $EXTENSION_REPEAT_STATE_CLASS_DESCRIPTOR->isAutoPlay(Ljava/lang/Enum;)Z
|
||||||
|
move-result v$freeRegister
|
||||||
|
if-eqz v$freeRegister, :ignore
|
||||||
|
new-instance v0, ${directReference.definingClass}
|
||||||
|
const/4 v1, 0x3
|
||||||
|
const/4 v2, 0x0
|
||||||
|
invoke-direct {v0, v1, v2, v2}, $directReference
|
||||||
|
iget-object v3, p0, $getReference
|
||||||
|
invoke-virtual {v3, v0}, $virtualReference
|
||||||
|
return-void
|
||||||
|
:ignore
|
||||||
|
nop
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getContext().apply {
|
||||||
|
addEntryValues(
|
||||||
|
"revanced_change_shorts_repeat_state_entries",
|
||||||
|
"@string/revanced_change_shorts_repeat_state_entry_pause",
|
||||||
|
)
|
||||||
|
addEntryValues(
|
||||||
|
"revanced_change_shorts_repeat_state_entry_values",
|
||||||
|
"END_SCREEN",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_19_34_or_greater) {
|
if (is_19_34_or_greater) {
|
||||||
shortsHUDFeatureFingerprint.injectLiteralInstructionBooleanCall(
|
shortsHUDFeatureFingerprint.injectLiteralInstructionBooleanCall(
|
||||||
SHORTS_HUD_FEATURE_FLAG,
|
SHORTS_HUD_FEATURE_FLAG,
|
||||||
|
@ -16,6 +16,7 @@ import app.revanced.patches.youtube.utils.resourceid.totalTime
|
|||||||
import app.revanced.patches.youtube.utils.resourceid.varispeedUnavailableTitle
|
import app.revanced.patches.youtube.utils.resourceid.varispeedUnavailableTitle
|
||||||
import app.revanced.patches.youtube.utils.resourceid.videoQualityBottomSheet
|
import app.revanced.patches.youtube.utils.resourceid.videoQualityBottomSheet
|
||||||
import app.revanced.patches.youtube.utils.sponsorblock.sponsorBlockBytecodePatch
|
import app.revanced.patches.youtube.utils.sponsorblock.sponsorBlockBytecodePatch
|
||||||
|
import app.revanced.util.containsLiteralInstruction
|
||||||
import app.revanced.util.fingerprint.legacyFingerprint
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.indexOfFirstInstruction
|
import app.revanced.util.indexOfFirstInstruction
|
||||||
@ -23,6 +24,7 @@ import app.revanced.util.or
|
|||||||
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.Method
|
||||||
|
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
|
||||||
|
|
||||||
internal val bottomSheetMenuItemBuilderFingerprint = legacyFingerprint(
|
internal val bottomSheetMenuItemBuilderFingerprint = legacyFingerprint(
|
||||||
@ -219,6 +221,29 @@ internal val videoEndFingerprint = legacyFingerprint(
|
|||||||
literals = listOf(45368273L),
|
literals = listOf(45368273L),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This fingerprint is compatible with all versions of YouTube starting from v18.29.38 to supported versions.
|
||||||
|
* This method is invoked only in Shorts.
|
||||||
|
* Accurate video information is invoked even when the user moves Shorts upward or downward.
|
||||||
|
*/
|
||||||
|
internal val videoIdFingerprintShorts = legacyFingerprint(
|
||||||
|
name = "videoIdFingerprintShorts",
|
||||||
|
returnType = "V",
|
||||||
|
parameters = listOf(PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR),
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.INVOKE_INTERFACE,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT
|
||||||
|
),
|
||||||
|
customFingerprint = custom@{ method, _ ->
|
||||||
|
if (method.containsLiteralInstruction(45365621L))
|
||||||
|
return@custom true
|
||||||
|
|
||||||
|
method.indexOfFirstInstruction {
|
||||||
|
getReference<FieldReference>()?.name == "reelWatchEndpoint"
|
||||||
|
} >= 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Several instructions are added to this method by different patches.
|
* Several instructions are added to this method by different patches.
|
||||||
* Therefore, patches using this fingerprint should not use the [Opcode] pattern,
|
* Therefore, patches using this fingerprint should not use the [Opcode] pattern,
|
||||||
|
@ -65,6 +65,8 @@ var is_20_03_or_greater = false
|
|||||||
private set
|
private set
|
||||||
var is_20_05_or_greater = false
|
var is_20_05_or_greater = false
|
||||||
private set
|
private set
|
||||||
|
var is_20_09_or_greater = false
|
||||||
|
private set
|
||||||
var is_20_10_or_greater = false
|
var is_20_10_or_greater = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -112,6 +114,7 @@ val versionCheckPatch = resourcePatch(
|
|||||||
is_20_02_or_greater = 250299000 <= playStoreServicesVersion
|
is_20_02_or_greater = 250299000 <= playStoreServicesVersion
|
||||||
is_20_03_or_greater = 250405000 <= playStoreServicesVersion
|
is_20_03_or_greater = 250405000 <= playStoreServicesVersion
|
||||||
is_20_05_or_greater = 250605000 <= playStoreServicesVersion
|
is_20_05_or_greater = 250605000 <= playStoreServicesVersion
|
||||||
|
is_20_09_or_greater = 251006000 <= playStoreServicesVersion
|
||||||
is_20_10_or_greater = 251105000 <= playStoreServicesVersion
|
is_20_10_or_greater = 251105000 <= playStoreServicesVersion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package app.revanced.patches.youtube.video.information
|
|||||||
import app.revanced.patches.youtube.utils.PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR
|
import app.revanced.patches.youtube.utils.PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR
|
||||||
import app.revanced.patches.youtube.utils.resourceid.notificationBigPictureIconWidth
|
import app.revanced.patches.youtube.utils.resourceid.notificationBigPictureIconWidth
|
||||||
import app.revanced.patches.youtube.utils.resourceid.qualityAuto
|
import app.revanced.patches.youtube.utils.resourceid.qualityAuto
|
||||||
import app.revanced.util.containsLiteralInstruction
|
|
||||||
import app.revanced.util.fingerprint.legacyFingerprint
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.indexOfFirstInstruction
|
import app.revanced.util.indexOfFirstInstruction
|
||||||
@ -133,29 +132,6 @@ fun indexOfPlayerResponseModelInterfaceInstruction(methodDef: Method) =
|
|||||||
getReference<MethodReference>()?.definingClass == PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR
|
getReference<MethodReference>()?.definingClass == PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This fingerprint is compatible with all versions of YouTube starting from v18.29.38 to supported versions.
|
|
||||||
* This method is invoked only in Shorts.
|
|
||||||
* Accurate video information is invoked even when the user moves Shorts upward or downward.
|
|
||||||
*/
|
|
||||||
internal val videoIdFingerprintShorts = legacyFingerprint(
|
|
||||||
name = "videoIdFingerprintShorts",
|
|
||||||
returnType = "V",
|
|
||||||
parameters = listOf(PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR),
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.INVOKE_INTERFACE,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT
|
|
||||||
),
|
|
||||||
customFingerprint = custom@{ method, _ ->
|
|
||||||
if (method.containsLiteralInstruction(45365621L))
|
|
||||||
return@custom true
|
|
||||||
|
|
||||||
method.indexOfFirstInstruction {
|
|
||||||
getReference<FieldReference>()?.name == "reelWatchEndpoint"
|
|
||||||
} >= 0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
internal val videoQualityListFingerprint = legacyFingerprint(
|
internal val videoQualityListFingerprint = legacyFingerprint(
|
||||||
name = "videoQualityListFingerprint",
|
name = "videoQualityListFingerprint",
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
|
@ -19,6 +19,7 @@ import app.revanced.patches.youtube.utils.extension.Constants.SHARED_PATH
|
|||||||
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
|
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
||||||
import app.revanced.patches.youtube.utils.videoEndFingerprint
|
import app.revanced.patches.youtube.utils.videoEndFingerprint
|
||||||
|
import app.revanced.patches.youtube.utils.videoIdFingerprintShorts
|
||||||
import app.revanced.patches.youtube.video.playerresponse.Hook
|
import app.revanced.patches.youtube.video.playerresponse.Hook
|
||||||
import app.revanced.patches.youtube.video.playerresponse.addPlayerResponseMethodHook
|
import app.revanced.patches.youtube.video.playerresponse.addPlayerResponseMethodHook
|
||||||
import app.revanced.patches.youtube.video.playerresponse.playerResponseMethodHookPatch
|
import app.revanced.patches.youtube.video.playerresponse.playerResponseMethodHookPatch
|
||||||
|
@ -98,13 +98,11 @@
|
|||||||
<item>@string/revanced_change_shorts_repeat_state_entry_default</item>
|
<item>@string/revanced_change_shorts_repeat_state_entry_default</item>
|
||||||
<item>@string/revanced_change_shorts_repeat_state_entry_repeat</item>
|
<item>@string/revanced_change_shorts_repeat_state_entry_repeat</item>
|
||||||
<item>@string/revanced_change_shorts_repeat_state_entry_auto_play</item>
|
<item>@string/revanced_change_shorts_repeat_state_entry_auto_play</item>
|
||||||
<item>@string/revanced_change_shorts_repeat_state_entry_pause</item>
|
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="revanced_change_shorts_repeat_state_entry_values">
|
<string-array name="revanced_change_shorts_repeat_state_entry_values">
|
||||||
<item>UNKNOWN</item>
|
<item>UNKNOWN</item>
|
||||||
<item>REPEAT</item>
|
<item>REPEAT</item>
|
||||||
<item>SINGLE_PLAY</item>
|
<item>SINGLE_PLAY</item>
|
||||||
<item>END_SCREEN</item>
|
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="revanced_default_video_quality_entries">
|
<string-array name="revanced_default_video_quality_entries">
|
||||||
<item>@string/quality_auto</item>
|
<item>@string/quality_auto</item>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user