mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-02 15:44:37 +02:00
feat(YouTube Music): Support version 7.25.52
https://github.com/inotia00/ReVanced_Extended/issues/2554
This commit is contained in:
parent
98f26a228a
commit
a27a04d1f2
@ -7,6 +7,8 @@ import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import app.revanced.extension.music.settings.Settings;
|
||||
import app.revanced.extension.music.utils.VideoUtils;
|
||||
|
||||
@ -40,6 +42,32 @@ public class ActionBarPatch {
|
||||
);
|
||||
}
|
||||
|
||||
private static final String senderView = "com.google.android.libraries.youtube.rendering.elements.sender_view";
|
||||
|
||||
public static boolean inAppDownloadButtonOnClick(Map mMap) {
|
||||
if (!Settings.EXTERNAL_DOWNLOADER_ACTION_BUTTON.get()) {
|
||||
return false;
|
||||
}
|
||||
if (mMap == null || mMap.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (!mMap.containsKey(senderView)) {
|
||||
return false;
|
||||
}
|
||||
if (!(getLithoViewFromMap(mMap, senderView, View.class) instanceof View view)) {
|
||||
return false;
|
||||
}
|
||||
VideoUtils.launchExternalDownloader();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rest of the implementation added by patch.
|
||||
*/
|
||||
private static Object getLithoViewFromMap(Map mMap, Object mObject, Class<?> mClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void inAppDownloadButtonOnClick(View view) {
|
||||
if (!Settings.EXTERNAL_DOWNLOADER_ACTION_BUTTON.get()) {
|
||||
return;
|
||||
|
@ -0,0 +1,98 @@
|
||||
package app.revanced.extension.music.patches.components;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.extension.shared.patches.components.ByteArrayFilterGroup;
|
||||
import app.revanced.extension.shared.patches.components.ByteArrayFilterGroupList;
|
||||
import app.revanced.extension.shared.patches.components.Filter;
|
||||
import app.revanced.extension.shared.patches.components.StringFilterGroup;
|
||||
import app.revanced.extension.music.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class ActionButtonsFilter extends Filter {
|
||||
private static final String VIDEO_ACTION_BAR_PATH_PREFIX = "video_action_bar.eml";
|
||||
|
||||
private final StringFilterGroup actionBarRule;
|
||||
private final StringFilterGroup bufferFilterPathRule;
|
||||
private final StringFilterGroup likeDislikeContainer;
|
||||
private final ByteArrayFilterGroupList bufferButtonsGroupList = new ByteArrayFilterGroupList();
|
||||
private final ByteArrayFilterGroup downloadButton;
|
||||
|
||||
public ActionButtonsFilter() {
|
||||
actionBarRule = new StringFilterGroup(
|
||||
null,
|
||||
VIDEO_ACTION_BAR_PATH_PREFIX
|
||||
);
|
||||
addIdentifierCallbacks(actionBarRule);
|
||||
|
||||
bufferFilterPathRule = new StringFilterGroup(
|
||||
null,
|
||||
"|ContainerType|button.eml|"
|
||||
);
|
||||
likeDislikeContainer = new StringFilterGroup(
|
||||
Settings.HIDE_ACTION_BUTTON_LIKE_DISLIKE,
|
||||
"segmented_like_dislike_button.eml"
|
||||
);
|
||||
addPathCallbacks(
|
||||
bufferFilterPathRule,
|
||||
likeDislikeContainer
|
||||
);
|
||||
|
||||
bufferButtonsGroupList.addAll(
|
||||
new ByteArrayFilterGroup(
|
||||
Settings.HIDE_ACTION_BUTTON_COMMENT,
|
||||
"yt_outline_message_bubble"
|
||||
),
|
||||
new ByteArrayFilterGroup(
|
||||
Settings.HIDE_ACTION_BUTTON_ADD_TO_PLAYLIST,
|
||||
"yt_outline_list_add"
|
||||
),
|
||||
new ByteArrayFilterGroup(
|
||||
Settings.HIDE_ACTION_BUTTON_SHARE,
|
||||
"yt_outline_share"
|
||||
),
|
||||
new ByteArrayFilterGroup(
|
||||
Settings.HIDE_ACTION_BUTTON_RADIO,
|
||||
"yt_outline_youtube_mix"
|
||||
)
|
||||
);
|
||||
downloadButton = new ByteArrayFilterGroup(
|
||||
Settings.HIDE_ACTION_BUTTON_DOWNLOAD,
|
||||
"music_download_button"
|
||||
);
|
||||
}
|
||||
|
||||
private boolean isEveryFilterGroupEnabled() {
|
||||
for (StringFilterGroup group : pathCallbacks)
|
||||
if (!group.isEnabled()) return false;
|
||||
|
||||
for (ByteArrayFilterGroup group : bufferButtonsGroupList)
|
||||
if (!group.isEnabled()) return false;
|
||||
|
||||
return downloadButton.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFiltered(String path, @Nullable String identifier, String allValue, byte[] protobufBufferArray,
|
||||
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
|
||||
if (!path.startsWith(VIDEO_ACTION_BAR_PATH_PREFIX)) {
|
||||
return false;
|
||||
}
|
||||
if (matchedGroup == actionBarRule && !isEveryFilterGroupEnabled()) {
|
||||
return false;
|
||||
}
|
||||
if (contentType == FilterContentType.PATH) {
|
||||
if (matchedGroup == bufferFilterPathRule) {
|
||||
if (!bufferButtonsGroupList.check(protobufBufferArray).isFiltered()) {
|
||||
return false;
|
||||
}
|
||||
} else if (matchedGroup != likeDislikeContainer) {
|
||||
if (!downloadButton.check(protobufBufferArray).isFiltered()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.isFiltered(path, identifier, allValue, protobufBufferArray, matchedGroup, contentType, contentIndex);
|
||||
}
|
||||
}
|
@ -8,11 +8,16 @@ import android.annotation.SuppressLint;
|
||||
import android.graphics.Color;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import app.revanced.extension.music.settings.Settings;
|
||||
import app.revanced.extension.music.shared.VideoType;
|
||||
import app.revanced.extension.music.utils.VideoUtils;
|
||||
import app.revanced.extension.shared.utils.Logger;
|
||||
import app.revanced.extension.shared.utils.Utils;
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public class PlayerPatch {
|
||||
@ -150,9 +155,22 @@ public class PlayerPatch {
|
||||
}
|
||||
|
||||
public static void shuffleTracks() {
|
||||
shuffleTracks(false);
|
||||
}
|
||||
|
||||
public static void shuffleTracksWithDelay() {
|
||||
shuffleTracks(true);
|
||||
}
|
||||
|
||||
private static void shuffleTracks(boolean needDelay) {
|
||||
if (!Settings.ALWAYS_SHUFFLE.get())
|
||||
return;
|
||||
VideoUtils.shuffleTracks();
|
||||
|
||||
if (needDelay) {
|
||||
Utils.runOnMainThreadDelayed(VideoUtils::shuffleTracks, 1000);
|
||||
} else {
|
||||
VideoUtils.shuffleTracks();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean rememberRepeatState(boolean original) {
|
||||
|
@ -2,8 +2,10 @@ package app.revanced.extension.music.patches.utils;
|
||||
|
||||
import static app.revanced.extension.shared.returnyoutubedislike.ReturnYouTubeDislike.Vote;
|
||||
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.extension.music.returnyoutubedislike.ReturnYouTubeDislike;
|
||||
@ -18,6 +20,45 @@ import app.revanced.extension.shared.utils.Logger;
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ReturnYouTubeDislikePatch {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* <p>
|
||||
* Called when a litho text component is initially created,
|
||||
* and also when a Span is later reused again (such as scrolling off/on screen).
|
||||
* <p>
|
||||
* This method is sometimes called on the main thread, but it usually is called _off_ the main thread.
|
||||
* This method can be called multiple times for the same UI element (including after dislikes was added).
|
||||
*
|
||||
* @param original Original char sequence was created or reused by Litho.
|
||||
* @return The original char sequence (if nothing should change), or a replacement char sequence that contains dislikes.
|
||||
*/
|
||||
public static CharSequence onLithoTextLoaded(@NonNull Object conversionContext,
|
||||
@NonNull CharSequence original) {
|
||||
try {
|
||||
if (!Settings.RYD_ENABLED.get()) {
|
||||
return original;
|
||||
}
|
||||
|
||||
String conversionContextString = conversionContext.toString();
|
||||
|
||||
if (!conversionContextString.contains("segmented_like_dislike_button.eml")) {
|
||||
return original;
|
||||
}
|
||||
ReturnYouTubeDislike videoData = currentVideoData;
|
||||
if (videoData == null) {
|
||||
return original; // User enabled RYD while a video was on screen.
|
||||
}
|
||||
if (!(original instanceof Spanned)) {
|
||||
original = new SpannableString(original);
|
||||
}
|
||||
return videoData.getDislikesSpan((Spanned) original, true);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "onLithoTextLoaded failure", ex);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* RYD data for the current video on screen.
|
||||
*/
|
||||
@ -49,7 +90,7 @@ public class ReturnYouTubeDislikePatch {
|
||||
if (videoData == null) {
|
||||
return original; // User enabled RYD while a video was on screen.
|
||||
}
|
||||
return videoData.getDislikesSpan(original);
|
||||
return videoData.getDislikesSpan(original, false);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "onSpannedCreated failure", ex);
|
||||
}
|
||||
|
@ -74,8 +74,6 @@ public class ReturnYouTubeDislike {
|
||||
*/
|
||||
private static final char MIDDLE_SEPARATOR_CHARACTER = '◎'; // 'bullseye'
|
||||
|
||||
private static final int SEPARATOR_COLOR = 872415231;
|
||||
|
||||
/**
|
||||
* Cached lookup of all video ids.
|
||||
*/
|
||||
@ -99,19 +97,11 @@ public class ReturnYouTubeDislike {
|
||||
@GuardedBy("ReturnYouTubeDislike.class")
|
||||
private static NumberFormat dislikePercentageFormatter;
|
||||
|
||||
public static final Rect leftSeparatorBounds;
|
||||
private static final Rect middleSeparatorBounds;
|
||||
public static Rect leftSeparatorBounds;
|
||||
private static Rect middleSeparatorBounds;
|
||||
|
||||
|
||||
static {
|
||||
DisplayMetrics dp = Objects.requireNonNull(Utils.getContext()).getResources().getDisplayMetrics();
|
||||
|
||||
leftSeparatorBounds = new Rect(0, 0,
|
||||
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1.2f, dp),
|
||||
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, dp));
|
||||
final int middleSeparatorSize =
|
||||
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3.7f, dp);
|
||||
middleSeparatorBounds = new Rect(0, 0, middleSeparatorSize, middleSeparatorSize);
|
||||
|
||||
ReturnYouTubeDislikeApi.toastOnConnectionError = Settings.RYD_TOAST_ON_CONNECTION_ERROR.get();
|
||||
}
|
||||
|
||||
@ -150,9 +140,26 @@ public class ReturnYouTubeDislike {
|
||||
@GuardedBy("this")
|
||||
private SpannableString replacementLikeDislikeSpan;
|
||||
|
||||
|
||||
/**
|
||||
* Color of the left and middle separator, based on the color of the right separator.
|
||||
* It's unknown where YT gets the color from, and the values here are approximated by hand.
|
||||
* Ideally, this would be the actual color YT uses at runtime.
|
||||
* <p>
|
||||
* Older versions before the 'Me' library tab use a slightly different color.
|
||||
* If spoofing was previously used and is now turned off,
|
||||
* or an old version was recently upgraded then the old colors are sometimes still used.
|
||||
*/
|
||||
private static int getSeparatorColor(boolean isLithoText) {
|
||||
return isLithoText
|
||||
? 0x29AAAAAA
|
||||
: 0x33FFFFFF;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static SpannableString createDislikeSpan(@NonNull Spanned oldSpannable,
|
||||
@NonNull RYDVoteData voteData) {
|
||||
@NonNull RYDVoteData voteData,
|
||||
boolean isLithoText) {
|
||||
CharSequence oldLikes = oldSpannable;
|
||||
|
||||
// YouTube creators can hide the like count on a video,
|
||||
@ -176,14 +183,27 @@ public class ReturnYouTubeDislike {
|
||||
}
|
||||
}
|
||||
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder("\u2009\u2009");
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder("\u2009");
|
||||
if (!isLithoText) {
|
||||
builder.append("\u2009");
|
||||
}
|
||||
final boolean compactLayout = Settings.RYD_COMPACT_LAYOUT.get();
|
||||
|
||||
if (middleSeparatorBounds == null) {
|
||||
final DisplayMetrics dp = Utils.getResources().getDisplayMetrics();
|
||||
leftSeparatorBounds = new Rect(0, 0,
|
||||
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1.2f, dp),
|
||||
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, isLithoText ? 23 : 25, dp));
|
||||
final int middleSeparatorSize =
|
||||
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3.7f, dp);
|
||||
middleSeparatorBounds = new Rect(0, 0, middleSeparatorSize, middleSeparatorSize);
|
||||
}
|
||||
|
||||
if (!compactLayout) {
|
||||
String leftSeparatorString = "\u200E "; // u200E = left to right character
|
||||
Spannable leftSeparatorSpan = new SpannableString(leftSeparatorString);
|
||||
ShapeDrawable shapeDrawable = new ShapeDrawable(new RectShape());
|
||||
shapeDrawable.getPaint().setColor(SEPARATOR_COLOR);
|
||||
shapeDrawable.getPaint().setColor(getSeparatorColor(isLithoText));
|
||||
shapeDrawable.setBounds(leftSeparatorBounds);
|
||||
leftSeparatorSpan.setSpan(new VerticallyCenteredImageSpan(shapeDrawable), 1, 2,
|
||||
Spannable.SPAN_INCLUSIVE_EXCLUSIVE); // drawable cannot overwrite RTL or LTR character
|
||||
@ -200,7 +220,7 @@ public class ReturnYouTubeDislike {
|
||||
final int shapeInsertionIndex = middleSeparatorString.length() / 2;
|
||||
Spannable middleSeparatorSpan = new SpannableString(middleSeparatorString);
|
||||
ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());
|
||||
shapeDrawable.getPaint().setColor(SEPARATOR_COLOR);
|
||||
shapeDrawable.getPaint().setColor(getSeparatorColor(isLithoText));
|
||||
shapeDrawable.setBounds(middleSeparatorBounds);
|
||||
// Use original text width if using Rolling Number,
|
||||
// to ensure the replacement styled span has the same width as the measured String,
|
||||
@ -416,12 +436,12 @@ public class ReturnYouTubeDislike {
|
||||
* @return the replacement span containing dislikes, or the original span if RYD is not available.
|
||||
*/
|
||||
@NonNull
|
||||
public synchronized Spanned getDislikesSpan(@NonNull Spanned original) {
|
||||
return waitForFetchAndUpdateReplacementSpan(original);
|
||||
public synchronized Spanned getDislikesSpan(@NonNull Spanned original, boolean isLithoText) {
|
||||
return waitForFetchAndUpdateReplacementSpan(original, isLithoText);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Spanned waitForFetchAndUpdateReplacementSpan(@NonNull Spanned original) {
|
||||
private Spanned waitForFetchAndUpdateReplacementSpan(@NonNull Spanned original, boolean isLithoText) {
|
||||
try {
|
||||
RYDVoteData votingData = getFetchData(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH);
|
||||
if (votingData == null) {
|
||||
@ -456,7 +476,7 @@ public class ReturnYouTubeDislike {
|
||||
votingData.updateUsingVote(userVote);
|
||||
}
|
||||
originalDislikeSpan = original;
|
||||
replacementLikeDislikeSpan = createDislikeSpan(original, votingData);
|
||||
replacementLikeDislikeSpan = createDislikeSpan(original, votingData, isLithoText);
|
||||
Logger.printDebug(() -> "Replaced: '" + originalDislikeSpan + "' with: '"
|
||||
+ replacementLikeDislikeSpan + "'" + " using video: " + videoId);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package app.revanced.patches.music.actionbar.components
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
@ -8,7 +9,11 @@ import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.music.utils.extension.Constants.ACTIONBAR_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.music.utils.extension.Constants.COMPONENTS_PATH
|
||||
import app.revanced.patches.music.utils.patch.PatchList.HIDE_ACTION_BAR_COMPONENTS
|
||||
import app.revanced.patches.music.utils.playservice.is_7_17_or_greater
|
||||
import app.revanced.patches.music.utils.playservice.is_7_25_or_greater
|
||||
import app.revanced.patches.music.utils.playservice.versionCheckPatch
|
||||
import app.revanced.patches.music.utils.resourceid.likeDislikeContainer
|
||||
import app.revanced.patches.music.utils.resourceid.sharedResourceIdPatch
|
||||
import app.revanced.patches.music.utils.settings.CategoryType
|
||||
@ -17,6 +22,9 @@ import app.revanced.patches.music.utils.settings.addPreferenceWithIntent
|
||||
import app.revanced.patches.music.utils.settings.addSwitchPreference
|
||||
import app.revanced.patches.music.utils.settings.settingsPatch
|
||||
import app.revanced.patches.music.video.information.videoInformationPatch
|
||||
import app.revanced.patches.shared.litho.addLithoFilter
|
||||
import app.revanced.patches.shared.litho.lithoFilterPatch
|
||||
import app.revanced.util.findMethodOrThrow
|
||||
import app.revanced.util.fingerprint.matchOrThrow
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.getReference
|
||||
@ -30,6 +38,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import kotlin.math.min
|
||||
|
||||
private const val FILTER_CLASS_DESCRIPTOR =
|
||||
"$COMPONENTS_PATH/ActionButtonsFilter;"
|
||||
|
||||
@Suppress("unused")
|
||||
val actionBarComponentsPatch = bytecodePatch(
|
||||
HIDE_ACTION_BAR_COMPONENTS.title,
|
||||
@ -39,94 +50,127 @@ val actionBarComponentsPatch = bytecodePatch(
|
||||
|
||||
dependsOn(
|
||||
settingsPatch,
|
||||
lithoFilterPatch,
|
||||
sharedResourceIdPatch,
|
||||
videoInformationPatch,
|
||||
versionCheckPatch,
|
||||
)
|
||||
|
||||
execute {
|
||||
if (is_7_17_or_greater) {
|
||||
browseSectionListReloadEndpointFingerprint.methodOrThrow().apply {
|
||||
val targetIndex = indexOfGetLithoViewFromMapInstruction(this)
|
||||
val targetReference = getInstruction<ReferenceInstruction>(targetIndex).reference
|
||||
|
||||
actionBarComponentFingerprint.matchOrThrow().let {
|
||||
it.method.apply {
|
||||
// hook download button
|
||||
val addViewIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "addView"
|
||||
}
|
||||
val addViewRegister =
|
||||
getInstruction<FiveRegisterInstruction>(addViewIndex).registerD
|
||||
|
||||
addInstruction(
|
||||
addViewIndex + 1,
|
||||
"invoke-static {v$addViewRegister}, $ACTIONBAR_CLASS_DESCRIPTOR->inAppDownloadButtonOnClick(Landroid/view/View;)V"
|
||||
findMethodOrThrow(ACTIONBAR_CLASS_DESCRIPTOR) {
|
||||
name == "getLithoViewFromMap"
|
||||
}.addInstructions(
|
||||
0, """
|
||||
invoke-static {p0, p1, p2}, $targetReference
|
||||
move-result-object p1
|
||||
return-object p1
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
// hide action button label
|
||||
val noLabelIndex = indexOfFirstInstructionOrThrow {
|
||||
val reference = (this as? ReferenceInstruction)?.reference.toString()
|
||||
opcode == Opcode.INVOKE_DIRECT &&
|
||||
reference.endsWith("<init>(Landroid/content/Context;)V") &&
|
||||
!reference.contains("Lcom/google/android/libraries/youtube/common/ui/YouTubeButton;")
|
||||
} - 2
|
||||
val replaceIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_DIRECT &&
|
||||
(this as? ReferenceInstruction)?.reference.toString()
|
||||
.endsWith("Lcom/google/android/libraries/youtube/common/ui/YouTubeButton;-><init>(Landroid/content/Context;)V")
|
||||
} - 2
|
||||
val replaceInstruction = getInstruction<TwoRegisterInstruction>(replaceIndex)
|
||||
val replaceReference = getInstruction<ReferenceInstruction>(replaceIndex).reference
|
||||
|
||||
offlineVideoEndpointFingerprint.methodOrThrow().apply {
|
||||
addInstructionsWithLabels(
|
||||
replaceIndex + 1, """
|
||||
invoke-static {}, $ACTIONBAR_CLASS_DESCRIPTOR->hideActionBarLabel()Z
|
||||
move-result v${replaceInstruction.registerA}
|
||||
if-nez v${replaceInstruction.registerA}, :hidden
|
||||
iget-object v${replaceInstruction.registerA}, v${replaceInstruction.registerB}, $replaceReference
|
||||
""", ExternalLabel("hidden", getInstruction(noLabelIndex))
|
||||
0, """
|
||||
invoke-static {p2}, $ACTIONBAR_CLASS_DESCRIPTOR->inAppDownloadButtonOnClick(Ljava/util/Map;)Z
|
||||
move-result v0
|
||||
if-eqz v0, :ignore
|
||||
return-void
|
||||
""", ExternalLabel("ignore", getInstruction(0))
|
||||
)
|
||||
removeInstruction(replaceIndex)
|
||||
}
|
||||
|
||||
// hide action button
|
||||
val hasNextIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_INTERFACE &&
|
||||
getReference<MethodReference>()?.name == "hasNext"
|
||||
addLithoFilter(FILTER_CLASS_DESCRIPTOR)
|
||||
}
|
||||
|
||||
if (!is_7_25_or_greater) {
|
||||
actionBarComponentFingerprint.matchOrThrow().let {
|
||||
it.method.apply {
|
||||
// hook download button
|
||||
val addViewIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "addView"
|
||||
}
|
||||
val addViewRegister =
|
||||
getInstruction<FiveRegisterInstruction>(addViewIndex).registerD
|
||||
|
||||
addInstruction(
|
||||
addViewIndex + 1,
|
||||
"invoke-static {v$addViewRegister}, $ACTIONBAR_CLASS_DESCRIPTOR->inAppDownloadButtonOnClick(Landroid/view/View;)V"
|
||||
)
|
||||
|
||||
// hide action button label
|
||||
val noLabelIndex = indexOfFirstInstructionOrThrow {
|
||||
val reference = (this as? ReferenceInstruction)?.reference.toString()
|
||||
opcode == Opcode.INVOKE_DIRECT &&
|
||||
reference.endsWith("<init>(Landroid/content/Context;)V") &&
|
||||
!reference.contains("Lcom/google/android/libraries/youtube/common/ui/YouTubeButton;")
|
||||
} - 2
|
||||
val replaceIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_DIRECT &&
|
||||
(this as? ReferenceInstruction)?.reference.toString()
|
||||
.endsWith("Lcom/google/android/libraries/youtube/common/ui/YouTubeButton;-><init>(Landroid/content/Context;)V")
|
||||
} - 2
|
||||
val replaceInstruction = getInstruction<TwoRegisterInstruction>(replaceIndex)
|
||||
val replaceReference = getInstruction<ReferenceInstruction>(replaceIndex).reference
|
||||
|
||||
addInstructionsWithLabels(
|
||||
replaceIndex + 1, """
|
||||
invoke-static {}, $ACTIONBAR_CLASS_DESCRIPTOR->hideActionBarLabel()Z
|
||||
move-result v${replaceInstruction.registerA}
|
||||
if-nez v${replaceInstruction.registerA}, :hidden
|
||||
iget-object v${replaceInstruction.registerA}, v${replaceInstruction.registerB}, $replaceReference
|
||||
""", ExternalLabel("hidden", getInstruction(noLabelIndex))
|
||||
)
|
||||
removeInstruction(replaceIndex)
|
||||
|
||||
// hide action button
|
||||
val hasNextIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_INTERFACE &&
|
||||
getReference<MethodReference>()?.name == "hasNext"
|
||||
}
|
||||
val freeRegister = min(implementation!!.registerCount - parameters.size - 2, 15)
|
||||
|
||||
val spannedIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.returnType == "Landroid/text/Spanned;"
|
||||
}
|
||||
val spannedRegister =
|
||||
getInstruction<FiveRegisterInstruction>(spannedIndex).registerC
|
||||
val spannedReference = getInstruction<ReferenceInstruction>(spannedIndex).reference
|
||||
|
||||
addInstructionsWithLabels(
|
||||
spannedIndex + 1, """
|
||||
invoke-static {}, $ACTIONBAR_CLASS_DESCRIPTOR->hideActionButton()Z
|
||||
move-result v$freeRegister
|
||||
if-nez v$freeRegister, :hidden
|
||||
invoke-static {v$spannedRegister}, $spannedReference
|
||||
""", ExternalLabel("hidden", getInstruction(hasNextIndex))
|
||||
)
|
||||
removeInstruction(spannedIndex)
|
||||
|
||||
// set action button identifier
|
||||
val buttonTypeDownloadIndex = it.patternMatch!!.startIndex + 1
|
||||
val buttonTypeDownloadRegister =
|
||||
getInstruction<OneRegisterInstruction>(buttonTypeDownloadIndex).registerA
|
||||
|
||||
val buttonTypeIndex = it.patternMatch!!.endIndex - 1
|
||||
val buttonTypeRegister =
|
||||
getInstruction<OneRegisterInstruction>(buttonTypeIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
buttonTypeIndex + 2,
|
||||
"invoke-static {v$buttonTypeRegister}, $ACTIONBAR_CLASS_DESCRIPTOR->setButtonType(Ljava/lang/Object;)V"
|
||||
)
|
||||
|
||||
addInstruction(
|
||||
buttonTypeDownloadIndex,
|
||||
"invoke-static {v$buttonTypeDownloadRegister}, $ACTIONBAR_CLASS_DESCRIPTOR->setButtonTypeDownload(I)V"
|
||||
)
|
||||
}
|
||||
val freeRegister = min(implementation!!.registerCount - parameters.size - 2, 15)
|
||||
|
||||
val spannedIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.returnType == "Landroid/text/Spanned;"
|
||||
}
|
||||
val spannedRegister =
|
||||
getInstruction<FiveRegisterInstruction>(spannedIndex).registerC
|
||||
val spannedReference = getInstruction<ReferenceInstruction>(spannedIndex).reference
|
||||
|
||||
addInstructionsWithLabels(
|
||||
spannedIndex + 1, """
|
||||
invoke-static {}, $ACTIONBAR_CLASS_DESCRIPTOR->hideActionButton()Z
|
||||
move-result v$freeRegister
|
||||
if-nez v$freeRegister, :hidden
|
||||
invoke-static {v$spannedRegister}, $spannedReference
|
||||
""", ExternalLabel("hidden", getInstruction(hasNextIndex))
|
||||
)
|
||||
removeInstruction(spannedIndex)
|
||||
|
||||
// set action button identifier
|
||||
val buttonTypeDownloadIndex = it.patternMatch!!.startIndex + 1
|
||||
val buttonTypeDownloadRegister =
|
||||
getInstruction<OneRegisterInstruction>(buttonTypeDownloadIndex).registerA
|
||||
|
||||
val buttonTypeIndex = it.patternMatch!!.endIndex - 1
|
||||
val buttonTypeRegister =
|
||||
getInstruction<OneRegisterInstruction>(buttonTypeIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
buttonTypeIndex + 2,
|
||||
"invoke-static {v$buttonTypeRegister}, $ACTIONBAR_CLASS_DESCRIPTOR->setButtonType(Ljava/lang/Object;)V"
|
||||
)
|
||||
|
||||
addInstruction(
|
||||
buttonTypeDownloadIndex,
|
||||
"invoke-static {v$buttonTypeDownloadRegister}, $ACTIONBAR_CLASS_DESCRIPTOR->setButtonTypeDownload(I)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,11 +215,13 @@ val actionBarComponentsPatch = bytecodePatch(
|
||||
"revanced_hide_action_button_radio",
|
||||
"false"
|
||||
)
|
||||
addSwitchPreference(
|
||||
CategoryType.ACTION_BAR,
|
||||
"revanced_hide_action_button_label",
|
||||
"false"
|
||||
)
|
||||
if (!is_7_25_or_greater) {
|
||||
addSwitchPreference(
|
||||
CategoryType.ACTION_BAR,
|
||||
"revanced_hide_action_button_label",
|
||||
"false"
|
||||
)
|
||||
}
|
||||
addSwitchPreference(
|
||||
CategoryType.ACTION_BAR,
|
||||
"revanced_external_downloader_action",
|
||||
|
@ -2,9 +2,13 @@ package app.revanced.patches.music.actionbar.components
|
||||
|
||||
import app.revanced.patches.music.utils.resourceid.likeDislikeContainer
|
||||
import app.revanced.util.fingerprint.legacyFingerprint
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import app.revanced.util.or
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
internal val actionBarComponentFingerprint = legacyFingerprint(
|
||||
name = "actionBarComponentFingerprint",
|
||||
@ -22,9 +26,40 @@ internal val actionBarComponentFingerprint = legacyFingerprint(
|
||||
literals = listOf(99180L),
|
||||
)
|
||||
|
||||
internal val browseSectionListReloadEndpointFingerprint = legacyFingerprint(
|
||||
name = "browseSectionListReloadEndpointFingerprint",
|
||||
returnType = "V",
|
||||
parameters = listOf("L", "Ljava/util/Map;"),
|
||||
strings = listOf("request_mutator"),
|
||||
customFingerprint = { method, _ ->
|
||||
indexOfGetLithoViewFromMapInstruction(method) >= 0
|
||||
}
|
||||
)
|
||||
|
||||
internal fun indexOfGetLithoViewFromMapInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode == Opcode.INVOKE_STATIC &&
|
||||
reference?.returnType == "Ljava/lang/Object;" &&
|
||||
reference.parameterTypes ==
|
||||
listOf(
|
||||
"Ljava/util/Map;",
|
||||
"Ljava/lang/Object;",
|
||||
"Ljava/lang/Class;"
|
||||
)
|
||||
}
|
||||
|
||||
internal val likeDislikeContainerFingerprint = legacyFingerprint(
|
||||
name = "likeDislikeContainerFingerprint",
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
literals = listOf(likeDislikeContainer)
|
||||
)
|
||||
|
||||
internal val offlineVideoEndpointFingerprint = legacyFingerprint(
|
||||
name = "offlineVideoEndpointFingerprint",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf("L", "Ljava/util/Map;"),
|
||||
strings = listOf("Object is not an offlineable video: %s")
|
||||
)
|
||||
|
@ -1,5 +1,6 @@
|
||||
package app.revanced.patches.music.general.redirection
|
||||
|
||||
import app.revanced.util.containsLiteralInstruction
|
||||
import app.revanced.util.fingerprint.legacyFingerprint
|
||||
import app.revanced.util.or
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
@ -9,9 +10,9 @@ internal val dislikeButtonOnClickListenerFingerprint = legacyFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("Landroid/view/View;"),
|
||||
literals = listOf(53465L),
|
||||
customFingerprint = { method, _ ->
|
||||
method.name == "onClick"
|
||||
method.name == "onClick" &&
|
||||
(method.containsLiteralInstruction(53465L) || method.containsLiteralInstruction(98173L))
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -4,11 +4,12 @@ import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patches.music.general.oldstylelibraryshelf.oldStyleLibraryShelfPatch
|
||||
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.music.utils.compatibility.Constants.YOUTUBE_MUSIC_PACKAGE_NAME
|
||||
import app.revanced.patches.music.utils.extension.Constants.GENERAL_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.music.utils.extension.Constants.PATCH_STATUS_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.music.utils.patch.PatchList.SPOOF_APP_VERSION
|
||||
import app.revanced.patches.music.utils.playservice.is_7_18_or_greater
|
||||
import app.revanced.patches.music.utils.playservice.is_7_17_or_greater
|
||||
import app.revanced.patches.music.utils.playservice.is_7_25_or_greater
|
||||
import app.revanced.patches.music.utils.playservice.versionCheckPatch
|
||||
import app.revanced.patches.music.utils.settings.CategoryType
|
||||
import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus
|
||||
@ -30,7 +31,10 @@ private val spoofAppVersionBytecodePatch = bytecodePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
if (is_7_18_or_greater) {
|
||||
if (is_7_25_or_greater) {
|
||||
return@execute
|
||||
}
|
||||
if (is_7_17_or_greater) {
|
||||
findMethodOrThrow(PATCH_STATUS_CLASS_DESCRIPTOR) {
|
||||
name == "SpoofAppVersionDefaultString"
|
||||
}.replaceInstruction(
|
||||
@ -54,7 +58,16 @@ val spoofAppVersionPatch = resourcePatch(
|
||||
SPOOF_APP_VERSION.title,
|
||||
SPOOF_APP_VERSION.summary,
|
||||
) {
|
||||
compatibleWith(COMPATIBLE_PACKAGE)
|
||||
compatibleWith(
|
||||
YOUTUBE_MUSIC_PACKAGE_NAME(
|
||||
"6.20.51",
|
||||
"6.29.59",
|
||||
"6.42.55",
|
||||
"6.51.53",
|
||||
"7.06.54",
|
||||
"7.16.53",
|
||||
),
|
||||
)
|
||||
|
||||
dependsOn(
|
||||
spoofAppVersionBytecodePatch,
|
||||
@ -64,7 +77,11 @@ val spoofAppVersionPatch = resourcePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
if (is_7_18_or_greater) {
|
||||
if (is_7_25_or_greater) {
|
||||
println("WARNING: \"${SPOOF_APP_VERSION.title}\" is not supported in this version. Use YouTube Music 7.24.51 or earlier.")
|
||||
return@execute
|
||||
}
|
||||
if (is_7_17_or_greater) {
|
||||
appendAppVersion("7.16.53")
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ val cairoSplashAnimationPatch = bytecodePatch(
|
||||
|
||||
execute {
|
||||
if (!is_7_06_or_greater) {
|
||||
println("WARNING: This patch is not supported in this version. Use YouTube Music 7.06.54 or later.")
|
||||
println("WARNING: \"${DISABLE_CAIRO_SPLASH_ANIMATION.title}\" is not supported in this version. Use YouTube Music 7.06.54 or later.")
|
||||
return@execute
|
||||
} else if (!is_7_20_or_greater) {
|
||||
cairoSplashAnimationConfigFingerprint.injectLiteralInstructionBooleanCall(
|
||||
|
@ -23,6 +23,7 @@ import app.revanced.patches.music.utils.pendingIntentReceiverFingerprint
|
||||
import app.revanced.patches.music.utils.playservice.is_6_27_or_greater
|
||||
import app.revanced.patches.music.utils.playservice.is_6_42_or_greater
|
||||
import app.revanced.patches.music.utils.playservice.is_7_18_or_greater
|
||||
import app.revanced.patches.music.utils.playservice.is_7_25_or_greater
|
||||
import app.revanced.patches.music.utils.playservice.versionCheckPatch
|
||||
import app.revanced.patches.music.utils.resourceid.colorGrey
|
||||
import app.revanced.patches.music.utils.resourceid.darkBackground
|
||||
@ -821,8 +822,8 @@ val playerComponentsPatch = bytecodePatch(
|
||||
|
||||
// region patch for remember repeat state
|
||||
|
||||
repeatTrackFingerprint.matchOrThrow().let {
|
||||
it.method.apply {
|
||||
val (repeatTrackMethod, repeatTrackIndex) = repeatTrackFingerprint.matchOrThrow().let {
|
||||
with (it.method) {
|
||||
val targetIndex = it.patternMatch!!.endIndex
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
@ -832,6 +833,7 @@ val playerComponentsPatch = bytecodePatch(
|
||||
move-result v$targetRegister
|
||||
"""
|
||||
)
|
||||
Pair(this, targetIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@ -919,6 +921,13 @@ val playerComponentsPatch = bytecodePatch(
|
||||
"invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->shuffleTracks()V"
|
||||
)
|
||||
|
||||
if (is_7_25_or_greater) {
|
||||
repeatTrackMethod.addInstruction(
|
||||
repeatTrackIndex,
|
||||
"invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->shuffleTracksWithDelay()V"
|
||||
)
|
||||
}
|
||||
|
||||
addSwitchPreference(
|
||||
CategoryType.PLAYER,
|
||||
"revanced_remember_shuffle_state",
|
||||
|
@ -13,7 +13,8 @@ internal object Constants {
|
||||
"6.29.59", // This is the latest version that supports the 'Restore old player layout' setting.
|
||||
"6.42.55", // This is the latest version that supports Android 7.0
|
||||
"6.51.53", // This is the latest version of YouTube Music 6.xx.xx
|
||||
"7.16.53", // This is the latest version supported by the RVX patch.
|
||||
"7.16.53", // This is the latest version that supports the 'Spoof app version' patch.
|
||||
"7.25.52", // This is the latest version supported by the RVX patch.
|
||||
)
|
||||
)
|
||||
}
|
@ -15,12 +15,16 @@ var is_7_06_or_greater = false
|
||||
private set
|
||||
var is_7_13_or_greater = false
|
||||
private set
|
||||
var is_7_17_or_greater = false
|
||||
private set
|
||||
var is_7_18_or_greater = false
|
||||
private set
|
||||
var is_7_20_or_greater = false
|
||||
private set
|
||||
var is_7_23_or_greater = false
|
||||
private set
|
||||
var is_7_25_or_greater = false
|
||||
private set
|
||||
|
||||
val versionCheckPatch = resourcePatch(
|
||||
description = "versionCheckPatch",
|
||||
@ -41,8 +45,10 @@ val versionCheckPatch = resourcePatch(
|
||||
is_6_42_or_greater = 240999000 <= playStoreServicesVersion
|
||||
is_7_06_or_greater = 242499000 <= playStoreServicesVersion
|
||||
is_7_13_or_greater = 243199000 <= playStoreServicesVersion
|
||||
is_7_17_or_greater = 243530000 <= playStoreServicesVersion
|
||||
is_7_18_or_greater = 243699000 <= playStoreServicesVersion
|
||||
is_7_20_or_greater = 243899000 <= playStoreServicesVersion
|
||||
is_7_23_or_greater = 244199000 <= playStoreServicesVersion
|
||||
is_7_25_or_greater = 244399000 <= playStoreServicesVersion
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.music.utils.extension.Constants.UTILS_PATH
|
||||
import app.revanced.patches.music.utils.patch.PatchList.RETURN_YOUTUBE_DISLIKE
|
||||
import app.revanced.patches.music.utils.playservice.is_7_17_or_greater
|
||||
import app.revanced.patches.music.utils.playservice.is_7_25_or_greater
|
||||
import app.revanced.patches.music.utils.resourceid.sharedResourceIdPatch
|
||||
import app.revanced.patches.music.utils.settings.CategoryType
|
||||
import app.revanced.patches.music.utils.settings.ResourceUtils.PREFERENCE_CATEGORY_TAG_NAME
|
||||
@ -20,6 +22,8 @@ import app.revanced.patches.music.video.information.videoInformationPatch
|
||||
import app.revanced.patches.shared.dislikeFingerprint
|
||||
import app.revanced.patches.shared.likeFingerprint
|
||||
import app.revanced.patches.shared.removeLikeFingerprint
|
||||
import app.revanced.patches.shared.textcomponent.hookSpannableString
|
||||
import app.revanced.patches.shared.textcomponent.textComponentPatch
|
||||
import app.revanced.util.adoptChild
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
@ -37,7 +41,8 @@ private val returnYouTubeDislikeBytecodePatch = bytecodePatch(
|
||||
dependsOn(
|
||||
settingsPatch,
|
||||
sharedResourceIdPatch,
|
||||
videoInformationPatch
|
||||
videoInformationPatch,
|
||||
textComponentPatch,
|
||||
)
|
||||
|
||||
execute {
|
||||
@ -56,25 +61,31 @@ private val returnYouTubeDislikeBytecodePatch = bytecodePatch(
|
||||
)
|
||||
}
|
||||
|
||||
if (!is_7_25_or_greater) {
|
||||
textComponentFingerprint.methodOrThrow().apply {
|
||||
val insertIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_STATIC
|
||||
&& (this as ReferenceInstruction).reference.toString()
|
||||
.endsWith("Ljava/lang/CharSequence;")
|
||||
} + 2
|
||||
val insertRegister =
|
||||
getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||
|
||||
textComponentFingerprint.methodOrThrow().apply {
|
||||
val insertIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_STATIC
|
||||
&& (this as ReferenceInstruction).reference.toString()
|
||||
.endsWith("Ljava/lang/CharSequence;")
|
||||
} + 2
|
||||
val insertRegister =
|
||||
getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {v$insertRegister}, $EXTENSION_CLASS_DESCRIPTOR->onSpannedCreated(Landroid/text/Spanned;)Landroid/text/Spanned;
|
||||
move-result-object v$insertRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {v$insertRegister}, $EXTENSION_CLASS_DESCRIPTOR->onSpannedCreated(Landroid/text/Spanned;)Landroid/text/Spanned;
|
||||
move-result-object v$insertRegister
|
||||
"""
|
||||
)
|
||||
if (is_7_17_or_greater) {
|
||||
hookSpannableString(EXTENSION_CLASS_DESCRIPTOR, "onLithoTextLoaded")
|
||||
}
|
||||
|
||||
videoIdHook("$EXTENSION_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,6 @@ internal val musicPlaybackControlsTimeBarOnMeasureFingerprint = legacyFingerprin
|
||||
name = "musicPlaybackControlsTimeBarOnMeasureFingerprint",
|
||||
returnType = "V",
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.RETURN_VOID
|
||||
|
@ -111,7 +111,10 @@ private val sponsorBlockBytecodePatch = bytecodePatch(
|
||||
rectangleFieldName =
|
||||
musicPlaybackControlsTimeBarOnMeasureFingerprint.matchOrThrow().let {
|
||||
with(it.method) {
|
||||
val rectangleIndex = it.patternMatch!!.startIndex
|
||||
val rectangleIndex = indexOfFirstInstructionReversedOrThrow(it.patternMatch!!.endIndex) {
|
||||
opcode == Opcode.IGET_OBJECT &&
|
||||
getReference<FieldReference>()?.type == "Landroid/graphics/Rect;"
|
||||
}
|
||||
val rectangleReference =
|
||||
getInstruction<ReferenceInstruction>(rectangleIndex).reference
|
||||
(rectangleReference as FieldReference).name
|
||||
|
Loading…
x
Reference in New Issue
Block a user