diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/ResourceType.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/ResourceType.java new file mode 100644 index 000000000..48032017a --- /dev/null +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/ResourceType.java @@ -0,0 +1,57 @@ +package app.revanced.extension.shared; + +import java.util.HashMap; +import java.util.Map; + +public enum ResourceType { + ANIM("anim"), + ANIMATOR("animator"), + ARRAY("array"), + ATTR("attr"), + BOOL("bool"), + COLOR("color"), + DIMEN("dimen"), + DRAWABLE("drawable"), + FONT("font"), + FRACTION("fraction"), + ID("id"), + INTEGER("integer"), + INTERPOLATOR("interpolator"), + LAYOUT("layout"), + MENU("menu"), + MIPMAP("mipmap"), + NAVIGATION("navigation"), + PLURALS("plurals"), + RAW("raw"), + STRING("string"), + STYLE("style"), + STYLEABLE("styleable"), + TRANSITION("transition"), + VALUES("values"), + XML("xml"); + + private static final Map VALUE_MAP; + + static { + ResourceType[] values = values(); + VALUE_MAP = new HashMap<>(2 * values.length); + + for (ResourceType type : values) { + VALUE_MAP.put(type.value, type); + } + } + + public final String value; + + public static ResourceType fromValue(String value) { + ResourceType type = VALUE_MAP.get(value); + if (type == null) { + throw new IllegalArgumentException("Unknown resource type: " + value); + } + return type; + } + + ResourceType(String value) { + this.value = value; + } +} diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/Utils.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/Utils.java index db157c4a1..6f8574f8b 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/Utils.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/Utils.java @@ -54,8 +54,10 @@ import androidx.annotation.Nullable; import java.text.Bidi; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.concurrent.Callable; import java.util.concurrent.Future; @@ -148,12 +150,12 @@ public class Utils { /** * Hide a view by setting its layout height and width to 1dp. * - * @param condition The setting to check for hiding the view. + * @param setting The setting to check for hiding the view. * @param view The view to hide. */ - public static void hideViewBy0dpUnderCondition(BooleanSetting condition, View view) { - if (hideViewBy0dpUnderCondition(condition.get(), view)) { - Logger.printDebug(() -> "View hidden by setting: " + condition); + public static void hideViewBy0dpUnderCondition(BooleanSetting setting, View view) { + if (hideViewBy0dpUnderCondition(setting.get(), view)) { + Logger.printDebug(() -> "View hidden by setting: " + setting); } } @@ -165,22 +167,47 @@ public class Utils { */ public static boolean hideViewBy0dpUnderCondition(boolean condition, View view) { if (condition) { - hideViewByLayoutParams(view); + hideViewBy0dp(view); return true; } return false; } + /** + * Hide a view by setting its layout params to 0x0 + * @param view The view to hide. + */ + public static void hideViewBy0dp(View view) { + if (view instanceof LinearLayout) { + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(0, 0); + view.setLayoutParams(layoutParams); + } else if (view instanceof FrameLayout) { + FrameLayout.LayoutParams layoutParams2 = new FrameLayout.LayoutParams(0, 0); + view.setLayoutParams(layoutParams2); + } else if (view instanceof RelativeLayout) { + RelativeLayout.LayoutParams layoutParams3 = new RelativeLayout.LayoutParams(0, 0); + view.setLayoutParams(layoutParams3); + } else if (view instanceof Toolbar) { + Toolbar.LayoutParams layoutParams4 = new Toolbar.LayoutParams(0, 0); + view.setLayoutParams(layoutParams4); + } else { + ViewGroup.LayoutParams params = view.getLayoutParams(); + params.width = 0; + params.height = 0; + view.setLayoutParams(params); + } + } + /** * Hide a view by setting its visibility to GONE. * - * @param condition The setting to check for hiding the view. + * @param setting The setting to check for hiding the view. * @param view The view to hide. */ - public static void hideViewUnderCondition(BooleanSetting condition, View view) { - if (hideViewUnderCondition(condition.get(), view)) { - Logger.printDebug(() -> "View hidden by setting: " + condition); + public static void hideViewUnderCondition(BooleanSetting setting, View view) { + if (hideViewUnderCondition(setting.get(), view)) { + Logger.printDebug(() -> "View hidden by setting: " + setting); } } @@ -199,14 +226,14 @@ public class Utils { return false; } - public static void hideViewByRemovingFromParentUnderCondition(BooleanSetting condition, View view) { - if (hideViewByRemovingFromParentUnderCondition(condition.get(), view)) { - Logger.printDebug(() -> "View hidden by setting: " + condition); + public static void hideViewByRemovingFromParentUnderCondition(BooleanSetting setting, View view) { + if (hideViewByRemovingFromParentUnderCondition(setting.get(), view)) { + Logger.printDebug(() -> "View hidden by setting: " + setting); } } - public static boolean hideViewByRemovingFromParentUnderCondition(boolean setting, View view) { - if (setting) { + public static boolean hideViewByRemovingFromParentUnderCondition(boolean condition, View view) { + if (condition) { ViewParent parent = view.getParent(); if (parent instanceof ViewGroup parentGroup) { parentGroup.removeView(view); @@ -277,42 +304,42 @@ public class Utils { /** * @return zero, if the resource is not found. */ - @SuppressLint("DiscouragedApi") - public static int getResourceIdentifier(Context context, String resourceIdentifierName, String type) { - return context.getResources().getIdentifier(resourceIdentifierName, type, context.getPackageName()); + public static int getResourceIdentifier(ResourceType type, String resourceIdentifierName) { + return getResourceIdentifier(getContext(), type, resourceIdentifierName); } /** * @return zero, if the resource is not found. */ - public static int getResourceIdentifier(String resourceIdentifierName, String type) { - return getResourceIdentifier(getContext(), resourceIdentifierName, type); + @SuppressLint("DiscouragedApi") + public static int getResourceIdentifier(Context context, ResourceType type, String resourceIdentifierName) { + return context.getResources().getIdentifier(resourceIdentifierName, type.value, context.getPackageName()); } public static int getResourceInteger(String resourceIdentifierName) throws Resources.NotFoundException { - return getContext().getResources().getInteger(getResourceIdentifier(resourceIdentifierName, "integer")); + return getContext().getResources().getInteger(getResourceIdentifier(ResourceType.INTEGER, resourceIdentifierName)); } public static Animation getResourceAnimation(String resourceIdentifierName) throws Resources.NotFoundException { - return AnimationUtils.loadAnimation(getContext(), getResourceIdentifier(resourceIdentifierName, "anim")); + return AnimationUtils.loadAnimation(getContext(), getResourceIdentifier(ResourceType.ANIM, resourceIdentifierName)); } @ColorInt public static int getResourceColor(String resourceIdentifierName) throws Resources.NotFoundException { //noinspection deprecation - return getContext().getResources().getColor(getResourceIdentifier(resourceIdentifierName, "color")); + return getContext().getResources().getColor(getResourceIdentifier(ResourceType.COLOR, resourceIdentifierName)); } public static int getResourceDimensionPixelSize(String resourceIdentifierName) throws Resources.NotFoundException { - return getContext().getResources().getDimensionPixelSize(getResourceIdentifier(resourceIdentifierName, "dimen")); + return getContext().getResources().getDimensionPixelSize(getResourceIdentifier(ResourceType.DIMEN, resourceIdentifierName)); } public static float getResourceDimension(String resourceIdentifierName) throws Resources.NotFoundException { - return getContext().getResources().getDimension(getResourceIdentifier(resourceIdentifierName, "dimen")); + return getContext().getResources().getDimension(getResourceIdentifier(ResourceType.DIMEN, resourceIdentifierName)); } public static String[] getResourceStringArray(String resourceIdentifierName) throws Resources.NotFoundException { - return getContext().getResources().getStringArray(getResourceIdentifier(resourceIdentifierName, "array")); + return getContext().getResources().getStringArray(getResourceIdentifier(ResourceType.ARRAY, resourceIdentifierName)); } public interface MatchFilter { @@ -323,7 +350,7 @@ public class Utils { * Includes sub children. */ public static R getChildViewByResourceName(View view, String str) { - var child = view.findViewById(Utils.getResourceIdentifier(str, "id")); + var child = view.findViewById(Utils.getResourceIdentifier(ResourceType.ID, str)); if (child != null) { //noinspection unchecked return (R) child; @@ -718,34 +745,6 @@ public class Utils { || (type == ConnectivityManager.TYPE_BLUETOOTH) ? NetworkType.MOBILE : NetworkType.OTHER; } - /** - * Hide a view by setting its layout params to 0x0 - * @param view The view to hide. - */ - public static void hideViewByLayoutParams(View view) { - if (view instanceof LinearLayout) { - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(0, 0); - view.setLayoutParams(layoutParams); - } else if (view instanceof FrameLayout) { - FrameLayout.LayoutParams layoutParams2 = new FrameLayout.LayoutParams(0, 0); - view.setLayoutParams(layoutParams2); - } else if (view instanceof RelativeLayout) { - RelativeLayout.LayoutParams layoutParams3 = new RelativeLayout.LayoutParams(0, 0); - view.setLayoutParams(layoutParams3); - } else if (view instanceof Toolbar) { - Toolbar.LayoutParams layoutParams4 = new Toolbar.LayoutParams(0, 0); - view.setLayoutParams(layoutParams4); - } else if (view instanceof ViewGroup) { - ViewGroup.LayoutParams layoutParams5 = new ViewGroup.LayoutParams(0, 0); - view.setLayoutParams(layoutParams5); - } else { - ViewGroup.LayoutParams params = view.getLayoutParams(); - params.width = 0; - params.height = 0; - view.setLayoutParams(params); - } - } - /** * Creates a custom dialog with a styled layout, including a title, message, buttons, and an * optional EditText. The dialog's appearance adapts to the app's dark mode setting, with @@ -1517,4 +1516,18 @@ public class Utils { public static float clamp(float value, float lower, float upper) { return Math.max(lower, Math.min(value, upper)); } + + /** + * @param maxSize The maximum number of elements to keep in the map. + * @return A {@link LinkedHashMap} that automatically evicts the oldest entry + * when the size exceeds {@code maxSize}. + */ + public static Map createSizeRestrictedMap(int maxSize) { + return new LinkedHashMap<>(2 * maxSize) { + @Override + protected boolean removeEldestEntry(Entry eldest) { + return size() > maxSize; + } + }; + } } diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/checks/Check.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/checks/Check.java index 7c0c09a0f..a66be8418 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/checks/Check.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/checks/Check.java @@ -3,7 +3,6 @@ package app.revanced.extension.shared.checks; import static android.text.Html.FROM_HTML_MODE_COMPACT; import static app.revanced.extension.shared.StringRef.str; import static app.revanced.extension.shared.Utils.DialogFragmentOnStartAction; -import static app.revanced.extension.shared.Utils.dipToPixels; import android.annotation.SuppressLint; import android.app.Activity; @@ -24,6 +23,7 @@ import androidx.annotation.Nullable; import java.util.Collection; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.BaseSettings; @@ -127,7 +127,8 @@ abstract class Check { // Add icon to the dialog. ImageView iconView = new ImageView(activity); - iconView.setImageResource(Utils.getResourceIdentifier("revanced_ic_dialog_alert", "drawable")); + iconView.setImageResource(Utils.getResourceIdentifier( + ResourceType.DRAWABLE, "revanced_ic_dialog_alert")); iconView.setColorFilter(Utils.getAppForegroundColor(), PorterDuff.Mode.SRC_IN); iconView.setPadding(0, 0, 0, 0); LinearLayout.LayoutParams iconParams = new LinearLayout.LayoutParams( diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/fixes/redgifs/BaseFixRedgifsApiPatch.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/fixes/redgifs/BaseFixRedgifsApiPatch.java index b6fa2caa0..00ee6def3 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/fixes/redgifs/BaseFixRedgifsApiPatch.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/fixes/redgifs/BaseFixRedgifsApiPatch.java @@ -15,7 +15,6 @@ import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; - public abstract class BaseFixRedgifsApiPatch implements Interceptor { protected static BaseFixRedgifsApiPatch INSTANCE; public abstract String getDefaultUserAgent(); diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java index dc592b488..649583318 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/AbstractPreferenceFragment.java @@ -23,6 +23,7 @@ import androidx.annotation.Nullable; import java.util.Objects; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BooleanSetting; @@ -105,7 +106,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment { String preferenceResourceName = BaseSettings.SHOW_MENU_ICONS.get() ? "revanced_prefs_icons" : "revanced_prefs"; - final var identifier = Utils.getResourceIdentifier(preferenceResourceName, "xml"); + final var identifier = Utils.getResourceIdentifier(ResourceType.XML, preferenceResourceName); if (identifier == 0) return; addPreferencesFromResource(identifier); diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ColorPickerPreference.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ColorPickerPreference.java index a70a66e72..5c8b5837e 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ColorPickerPreference.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ColorPickerPreference.java @@ -32,6 +32,7 @@ import java.util.Locale; import java.util.regex.Pattern; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.Setting; import app.revanced.extension.shared.settings.StringSetting; @@ -171,7 +172,8 @@ public class ColorPickerPreference extends EditTextPreference { } // Set the widget layout to a custom layout containing the colored dot. - setWidgetLayoutResource(getResourceIdentifier("revanced_color_dot_widget", "layout")); + setWidgetLayoutResource(getResourceIdentifier( + ResourceType.LAYOUT, "revanced_color_dot_widget")); } /** @@ -208,9 +210,11 @@ public class ColorPickerPreference extends EditTextPreference { super.onBindView(view); widgetColorDot = view.findViewById(getResourceIdentifier( - "revanced_color_dot_widget", "id")); + ResourceType.ID, + "revanced_color_dot_widget")); widgetColorDot.setBackgroundResource(getResourceIdentifier( - "revanced_settings_circle_background", "drawable")); + ResourceType.DRAWABLE, + "revanced_settings_circle_background")); widgetColorDot.getBackground().setTint(currentColor | 0xFF000000); widgetColorDot.setAlpha(isEnabled() ? 1.0f : DISABLED_ALPHA); } @@ -286,10 +290,10 @@ public class ColorPickerPreference extends EditTextPreference { Context context = getContext(); // Inflate color picker view. - View colorPicker = LayoutInflater.from(context).inflate( - getResourceIdentifier("revanced_color_picker", "layout"), null); - dialogColorPickerView = colorPicker.findViewById( - getResourceIdentifier("revanced_color_picker_view", "id")); + View colorPicker = LayoutInflater.from(context).inflate(getResourceIdentifier( + ResourceType.LAYOUT, "revanced_color_picker"), null); + dialogColorPickerView = colorPicker.findViewById(getResourceIdentifier( + ResourceType.ID, "revanced_color_picker_view")); dialogColorPickerView.setColor(currentColor); // Horizontal layout for preview and EditText. diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/CustomDialogListPreference.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/CustomDialogListPreference.java index 4d0c1d5c1..e1b6de8c8 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/CustomDialogListPreference.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/CustomDialogListPreference.java @@ -13,6 +13,7 @@ import android.widget.*; import androidx.annotation.NonNull; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; /** @@ -54,11 +55,14 @@ public class CustomDialogListPreference extends ListPreference { view = inflater.inflate(layoutResourceId, parent, false); holder = new SubViewDataContainer(); holder.checkIcon = view.findViewById(Utils.getResourceIdentifier( - "revanced_check_icon", "id")); + ResourceType.ID, + "revanced_check_icon")); holder.placeholder = view.findViewById(Utils.getResourceIdentifier( - "revanced_check_icon_placeholder", "id")); + ResourceType.ID, + "revanced_check_icon_placeholder")); holder.itemText = view.findViewById(Utils.getResourceIdentifier( - "revanced_item_text", "id")); + ResourceType.ID, + "revanced_item_text")); view.setTag(holder); } else { holder = (SubViewDataContainer) view.getTag(); @@ -111,7 +115,7 @@ public class CustomDialogListPreference extends ListPreference { // Create custom adapter for the ListView. ListPreferenceArrayAdapter adapter = new ListPreferenceArrayAdapter( context, - Utils.getResourceIdentifier("revanced_custom_list_item_checked", "layout"), + Utils.getResourceIdentifier(ResourceType.LAYOUT, "revanced_custom_list_item_checked"), getEntries(), getEntryValues(), getValue() diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java index eeab17d1f..afaea833d 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java @@ -13,7 +13,9 @@ import java.net.HttpURLConnection; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -70,22 +72,15 @@ public class StreamingDataRequest { */ private static final int MAX_MILLISECONDS_TO_WAIT_FOR_FETCH = 20 * 1000; + /** + * Cache limit must be greater than the maximum number of videos open at once, + * which theoretically is more than 4 (3 Shorts + one regular minimized video). + * But instead use a much larger value, to handle if a video viewed a while ago + * is somehow still referenced. Each stream is a small array of Strings + * so memory usage is not a concern. + */ private static final Map cache = Collections.synchronizedMap( - new LinkedHashMap<>(100) { - /** - * Cache limit must be greater than the maximum number of videos open at once, - * which theoretically is more than 4 (3 Shorts + one regular minimized video). - * But instead use a much larger value, to handle if a video viewed a while ago - * is somehow still referenced. Each stream is a small array of Strings - * so memory usage is not a concern. - */ - private static final int CACHE_LIMIT = 50; - - @Override - protected boolean removeEldestEntry(Entry eldest) { - return size() > CACHE_LIMIT; // Evict the oldest entry if over the cache limit. - } - }); + Utils.createSizeRestrictedMap(50)); private static volatile ClientType lastSpoofedClientType; diff --git a/extensions/spotify/src/main/java/app/revanced/extension/spotify/layout/hide/createbutton/HideCreateButtonPatch.java b/extensions/spotify/src/main/java/app/revanced/extension/spotify/layout/hide/createbutton/HideCreateButtonPatch.java index 1ed2e771f..82f2ea0f3 100644 --- a/extensions/spotify/src/main/java/app/revanced/extension/spotify/layout/hide/createbutton/HideCreateButtonPatch.java +++ b/extensions/spotify/src/main/java/app/revanced/extension/spotify/layout/hide/createbutton/HideCreateButtonPatch.java @@ -1,6 +1,7 @@ package app.revanced.extension.spotify.layout.hide.createbutton; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.spotify.shared.ComponentFilters.ComponentFilter; import app.revanced.extension.spotify.shared.ComponentFilters.ResourceIdComponentFilter; import app.revanced.extension.spotify.shared.ComponentFilters.StringComponentFilter; @@ -15,7 +16,7 @@ public final class HideCreateButtonPatch { * The main approach used is matching the resource id for the Create button title. */ private static final List CREATE_BUTTON_COMPONENT_FILTERS = List.of( - new ResourceIdComponentFilter("navigationbar_musicappitems_create_title", "string"), + new ResourceIdComponentFilter(ResourceType.STRING, "navigationbar_musicappitems_create_title"), // Temporary fallback and fix for APKs merged with AntiSplit-M not having resources properly encoded, // and thus getting the resource identifier for the Create button title always return 0. // FIXME: Remove this once the above issue is no longer relevant. @@ -27,7 +28,7 @@ public final class HideCreateButtonPatch { * Used in older versions of the app. */ private static final ResourceIdComponentFilter OLD_CREATE_BUTTON_COMPONENT_FILTER = - new ResourceIdComponentFilter("bottom_navigation_bar_create_tab_title", "string"); + new ResourceIdComponentFilter(ResourceType.STRING, "bottom_navigation_bar_create_tab_title"); /** * Injection point. This method is called on every navigation bar item to check whether it is the Create button. diff --git a/extensions/spotify/src/main/java/app/revanced/extension/spotify/shared/ComponentFilters.java b/extensions/spotify/src/main/java/app/revanced/extension/spotify/shared/ComponentFilters.java index 21f1dd3e3..599c397c9 100644 --- a/extensions/spotify/src/main/java/app/revanced/extension/spotify/shared/ComponentFilters.java +++ b/extensions/spotify/src/main/java/app/revanced/extension/spotify/shared/ComponentFilters.java @@ -3,6 +3,7 @@ package app.revanced.extension.spotify.shared; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; public final class ComponentFilters { @@ -19,21 +20,26 @@ public final class ComponentFilters { public static final class ResourceIdComponentFilter implements ComponentFilter { public final String resourceName; - public final String resourceType; + public final ResourceType resourceType; // Android resources are always positive, so -1 is a valid sentinel value to indicate it has not been loaded. // 0 is returned when a resource has not been found. private int resourceId = -1; @Nullable private String stringfiedResourceId; + @Deprecated public ResourceIdComponentFilter(String resourceName, String resourceType) { + this(ResourceType.valueOf(resourceType), resourceName); + } + + public ResourceIdComponentFilter(ResourceType resourceType, String resourceName) { this.resourceName = resourceName; this.resourceType = resourceType; } public int getResourceId() { if (resourceId == -1) { - resourceId = Utils.getResourceIdentifier(resourceName, resourceType); + resourceId = Utils.getResourceIdentifier(resourceType, resourceName); } return resourceId; } diff --git a/extensions/twitch/src/main/java/app/revanced/extension/twitch/Utils.java b/extensions/twitch/src/main/java/app/revanced/extension/twitch/Utils.java index 73c363ff8..5db5b8b2f 100644 --- a/extensions/twitch/src/main/java/app/revanced/extension/twitch/Utils.java +++ b/extensions/twitch/src/main/java/app/revanced/extension/twitch/Utils.java @@ -1,14 +1,18 @@ package app.revanced.extension.twitch; +import app.revanced.extension.shared.ResourceType; + public class Utils { /* Called from SettingsPatch smali */ public static int getStringId(String name) { - return app.revanced.extension.shared.Utils.getResourceIdentifier(name, "string"); + return app.revanced.extension.shared.Utils.getResourceIdentifier( + ResourceType.STRING, name); } /* Called from SettingsPatch smali */ public static int getDrawableId(String name) { - return app.revanced.extension.shared.Utils.getResourceIdentifier(name, "drawable"); + return app.revanced.extension.shared.Utils.getResourceIdentifier( + ResourceType.DRAWABLE, name); } } diff --git a/extensions/twitch/src/main/java/app/revanced/extension/twitch/settings/AppCompatActivityHook.java b/extensions/twitch/src/main/java/app/revanced/extension/twitch/settings/AppCompatActivityHook.java index e617cf9b2..b071d2cf1 100644 --- a/extensions/twitch/src/main/java/app/revanced/extension/twitch/settings/AppCompatActivityHook.java +++ b/extensions/twitch/src/main/java/app/revanced/extension/twitch/settings/AppCompatActivityHook.java @@ -2,16 +2,19 @@ package app.revanced.extension.twitch.settings; import android.content.Intent; import android.os.Bundle; + import androidx.appcompat.app.ActionBar; + +import java.util.ArrayList; +import java.util.List; + import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.twitch.settings.preference.ReVancedPreferenceFragment; import tv.twitch.android.feature.settings.menu.SettingsMenuGroup; import tv.twitch.android.settings.SettingsActivity; -import java.util.ArrayList; -import java.util.List; - /** * Hooks AppCompatActivity. *

@@ -105,7 +108,7 @@ public class AppCompatActivityHook { base.getFragmentManager() .beginTransaction() - .replace(Utils.getResourceIdentifier("fragment_container", "id"), fragment) + .replace(Utils.getResourceIdentifier(ResourceType.ID, "fragment_container"), fragment) .commit(); return true; } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/AlternativeThumbnailsPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/AlternativeThumbnailsPatch.java index a4dd50fcc..0b07c17b9 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/AlternativeThumbnailsPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/AlternativeThumbnailsPatch.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.ExecutionException; @@ -505,14 +504,8 @@ public final class AlternativeThumbnailsPatch { * Cache used to verify if an alternative thumbnails exists for a given video id. */ @GuardedBy("itself") - private static final Map altVideoIdLookup = new LinkedHashMap<>(100) { - private static final int CACHE_LIMIT = 1000; - - @Override - protected boolean removeEldestEntry(Entry eldest) { - return size() > CACHE_LIMIT; // Evict the oldest entry if over the cache limit. - } - }; + private static final Map altVideoIdLookup = + Utils.createSizeRestrictedMap(1000); private static VerifiedQualities getVerifiedQualities(@NonNull String videoId, boolean returnNullIfDoesNotExist) { synchronized (altVideoIdLookup) { diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ChangeHeaderPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ChangeHeaderPatch.java index ed5bcec07..f2a225aa9 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ChangeHeaderPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ChangeHeaderPatch.java @@ -7,6 +7,7 @@ import androidx.annotation.Nullable; import java.util.Objects; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.youtube.settings.Settings; @@ -40,7 +41,7 @@ public class ChangeHeaderPatch { return null; } - final int identifier = Utils.getResourceIdentifier(attributeName, "attr"); + final int identifier = Utils.getResourceIdentifier(ResourceType.ATTR, attributeName); if (identifier == 0) { // Identifier is zero if custom header setting was included in imported settings // and a custom image was not included during patching. @@ -62,7 +63,7 @@ public class ChangeHeaderPatch { ? "_dark" : "_light"); - final int identifier = Utils.getResourceIdentifier(drawableFullName, "drawable"); + final int identifier = Utils.getResourceIdentifier(ResourceType.DRAWABLE, drawableFullName); if (identifier == 0) { Logger.printDebug(() -> "Could not find drawable: " + drawableFullName); Settings.HEADER_LOGO.resetToDefault(); diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DownloadsPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DownloadsPatch.java index 7950c8b21..17115ec93 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DownloadsPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/DownloadsPatch.java @@ -21,7 +21,7 @@ public final class DownloadsPatch { /** * Injection point. */ - public static void activityCreated(Activity mainActivity) { + public static void setMainActivity(Activity mainActivity) { activityRef = new WeakReference<>(mainActivity); } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HidePlayerOverlayButtonsPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HidePlayerOverlayButtonsPatch.java index 070c330d0..2f666f990 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HidePlayerOverlayButtonsPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HidePlayerOverlayButtonsPatch.java @@ -5,6 +5,7 @@ import android.view.ViewGroup; import android.widget.ImageView; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.youtube.settings.Settings; @@ -27,6 +28,15 @@ public final class HidePlayerOverlayButtonsPatch { return Settings.HIDE_CAST_BUTTON.get() ? View.GONE : original; } + /** + * Injection point. + */ + public static boolean getCastButtonOverrideV2(boolean original) { + if (Settings.HIDE_CAST_BUTTON.get()) return false; + + return original; + } + /** * Injection point. */ @@ -38,10 +48,10 @@ public final class HidePlayerOverlayButtonsPatch { = Settings.HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS.get(); private static final int PLAYER_CONTROL_PREVIOUS_BUTTON_TOUCH_AREA_ID = - Utils.getResourceIdentifier("player_control_previous_button_touch_area", "id"); + Utils.getResourceIdentifier(ResourceType.ID, "player_control_previous_button_touch_area"); private static final int PLAYER_CONTROL_NEXT_BUTTON_TOUCH_AREA_ID = - Utils.getResourceIdentifier("player_control_next_button_touch_area", "id"); + Utils.getResourceIdentifier(ResourceType.ID, "player_control_next_button_touch_area"); /** * Injection point. diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HideSeekbarPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HideSeekbarPatch.java index 98065d7ec..521e7812b 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HideSeekbarPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/HideSeekbarPatch.java @@ -4,7 +4,17 @@ import app.revanced.extension.youtube.settings.Settings; @SuppressWarnings("unused") public class HideSeekbarPatch { + /** + * Injection point. + */ public static boolean hideSeekbar() { return Settings.HIDE_SEEKBAR.get(); } + + /** + * Injection point. + */ + public static boolean useFullscreenLargeSeekbar(boolean original) { + return Settings.FULLSCREEN_LARGE_SEEKBAR.get(); + } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/MiniplayerPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/MiniplayerPatch.java index 7a7571162..e726c3616 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/MiniplayerPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/MiniplayerPatch.java @@ -13,6 +13,7 @@ import android.widget.TextView; import androidx.annotation.Nullable; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.Setting; import app.revanced.extension.youtube.settings.Settings; @@ -113,7 +114,7 @@ public final class MiniplayerPatch { * Resource is not present in older targets, and this field will be zero. */ private static final int MODERN_OVERLAY_SUBTITLE_TEXT - = Utils.getResourceIdentifier("modern_miniplayer_subtitle_text", "id"); + = Utils.getResourceIdentifier(ResourceType.ID, "modern_miniplayer_subtitle_text"); private static final MiniplayerType CURRENT_TYPE = Settings.MINIPLAYER_TYPE.get(); diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/NavigationButtonsPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/NavigationButtonsPatch.java index 7021cc6f9..e5ec52b77 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/NavigationButtonsPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/NavigationButtonsPatch.java @@ -62,6 +62,13 @@ public final class NavigationButtonsPatch { hideViewUnderCondition(Settings.HIDE_NAVIGATION_BUTTON_LABELS, navigationLabelsView); } + /** + * Injection point. + */ + public static boolean useAnimatedNavigationButtons(boolean original) { + return Settings.NAVIGATION_BAR_ANIMATIONS.get(); + } + /** * Injection point. */ diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/OpenShortsInRegularPlayerPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/OpenShortsInRegularPlayerPatch.java index e0a1e3c70..02fc01c9f 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/OpenShortsInRegularPlayerPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/OpenShortsInRegularPlayerPatch.java @@ -20,15 +20,6 @@ public class OpenShortsInRegularPlayerPatch { REGULAR_PLAYER_FULLSCREEN } - static { - if (!VersionCheckPatch.IS_19_46_OR_GREATER - && Settings.SHORTS_PLAYER_TYPE.get() == ShortsPlayerType.REGULAR_PLAYER_FULLSCREEN) { - // User imported newer settings to an older app target. - Logger.printInfo(() -> "Resetting " + Settings.SHORTS_PLAYER_TYPE); - Settings.SHORTS_PLAYER_TYPE.resetToDefault(); - } - } - private static WeakReference mainActivityRef = new WeakReference<>(null); private static volatile boolean overrideBackPressToExit; diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/OpenVideosFullscreenHookPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/OpenVideosFullscreenHookPatch.java index ff2d77874..9a7989d9a 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/OpenVideosFullscreenHookPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/OpenVideosFullscreenHookPatch.java @@ -24,18 +24,20 @@ public class OpenVideosFullscreenHookPatch { /** * Injection point. + * + * Returns negated value. */ - public static boolean openVideoFullscreenPortrait(boolean original) { + public static boolean doNotOpenVideoFullscreenPortrait(boolean original) { Boolean openFullscreen = openNextVideoFullscreen; if (openFullscreen != null) { openNextVideoFullscreen = null; - return openFullscreen; + return !openFullscreen; } if (!isFullScreenPatchIncluded()) { return original; } - return Settings.OPEN_VIDEOS_FULLSCREEN_PORTRAIT.get(); + return !Settings.OPEN_VIDEOS_FULLSCREEN_PORTRAIT.get(); } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/PlayerControlsPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/PlayerControlsPatch.java index a96999683..be7fe9119 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/PlayerControlsPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/PlayerControlsPatch.java @@ -42,7 +42,7 @@ public class PlayerControlsPatch { Logger.printDebug(() -> "fullscreen button visibility: " + (visibility == View.VISIBLE ? "VISIBLE" : - visibility == View.GONE ? "GONE" : "INVISIBLE")); + visibility == View.GONE ? "GONE" : "INVISIBLE")); fullscreenButtonVisibilityChanged(visibility == View.VISIBLE); } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/RemoveTrackingQueryParameterPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/RemoveTrackingQueryParameterPatch.java index 3b05a239a..67f645a05 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/RemoveTrackingQueryParameterPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/RemoveTrackingQueryParameterPatch.java @@ -1,5 +1,7 @@ package app.revanced.extension.youtube.patches; +import android.content.Intent; + import app.revanced.extension.youtube.settings.Settings; @SuppressWarnings("unused") @@ -7,8 +9,13 @@ public final class RemoveTrackingQueryParameterPatch { private static final String NEW_TRACKING_PARAMETER_REGEX = ".si=.+"; private static final String OLD_TRACKING_PARAMETER_REGEX = ".feature=.+"; + /** + * Injection point. + */ public static String sanitize(String url) { - if (!Settings.REMOVE_TRACKING_QUERY_PARAMETER.get()) return url; + if (!Settings.REMOVE_TRACKING_QUERY_PARAMETER.get()) { + return url; + } return url .replaceAll(NEW_TRACKING_PARAMETER_REGEX, "") diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/RemoveViewerDiscretionDialogPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/RemoveViewerDiscretionDialogPatch.java index 0260b2c69..6f2ea968d 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/RemoveViewerDiscretionDialogPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/RemoveViewerDiscretionDialogPatch.java @@ -1,19 +1,29 @@ package app.revanced.extension.youtube.patches; import android.app.AlertDialog; + +import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.Utils; import app.revanced.extension.youtube.settings.Settings; -/** @noinspection unused*/ +@SuppressWarnings("unused") public class RemoveViewerDiscretionDialogPatch { + + /** + * Injection point. + */ public static void confirmDialog(AlertDialog dialog) { - if (!Settings.REMOVE_VIEWER_DISCRETION_DIALOG.get()) { - // Since the patch replaces the AlertDialog#show() method, we need to call the original method here. - dialog.show(); + if (Settings.REMOVE_VIEWER_DISCRETION_DIALOG.get()) { + Logger.printDebug(() -> "Clicking alert dialog dismiss button"); + + final var button = dialog.getButton(AlertDialog.BUTTON_POSITIVE); + button.setSoundEffectsEnabled(false); + button.performClick(); return; } - final var button = dialog.getButton(AlertDialog.BUTTON_POSITIVE); - button.setSoundEffectsEnabled(false); - button.performClick(); + // Since the patch replaces the AlertDialog#show() method, we need to call the original method here. + Logger.printDebug(() -> "Showing alert dialog"); + dialog.show(); } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ShortsAutoplayPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ShortsAutoplayPatch.java index 9e5aff20b..e7de42136 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ShortsAutoplayPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/ShortsAutoplayPatch.java @@ -2,8 +2,6 @@ package app.revanced.extension.youtube.patches; import android.app.Activity; -import androidx.annotation.Nullable; - import java.lang.ref.WeakReference; import java.util.Objects; @@ -78,7 +76,7 @@ public class ShortsAutoplayPatch { /** * Injection point. */ - public static Enum changeShortsRepeatBehavior(@Nullable Enum original) { + public static Enum changeShortsRepeatBehavior(Enum original) { try { final boolean autoplay; @@ -95,19 +93,19 @@ public class ShortsAutoplayPatch { autoplay = Settings.SHORTS_AUTOPLAY.get(); } - final ShortsLoopBehavior behavior = autoplay + Enum overrideBehavior = (autoplay ? ShortsLoopBehavior.SINGLE_PLAY - : ShortsLoopBehavior.REPEAT; + : ShortsLoopBehavior.REPEAT).ytEnumValue; - if (behavior.ytEnumValue != null) { + if (overrideBehavior != null) { Logger.printDebug(() -> { String name = (original == null ? "unknown (null)" : original.name()); - return behavior == original + return overrideBehavior == original ? "Behavior setting is same as original. Using original: " + name - : "Changing Shorts repeat behavior from: " + name + " to: " + behavior.name(); + : "Changing Shorts repeat behavior from: " + name + " to: " + overrideBehavior.name(); }); - return behavior.ytEnumValue; + return overrideBehavior; } if (original == null) { @@ -118,13 +116,12 @@ public class ShortsAutoplayPatch { return unknown; } } catch (Exception ex) { - Logger.printException(() -> "changeShortsRepeatBehavior failure", ex); + Logger.printException(() -> "changeShortsRepeatState failure", ex); } return original; } - /** * Injection point. */ diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/VersionCheckPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/VersionCheckPatch.java index 2844b53db..e9b292986 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/VersionCheckPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/VersionCheckPatch.java @@ -19,5 +19,8 @@ public class VersionCheckPatch { public static final boolean IS_19_29_OR_GREATER = isVersionOrGreater("19.29.00"); @Deprecated public static final boolean IS_19_34_OR_GREATER = isVersionOrGreater("19.34.00"); - public static final boolean IS_19_46_OR_GREATER = isVersionOrGreater("19.46.00"); + + public static final boolean IS_20_21_OR_GREATER = isVersionOrGreater("20.21.00"); + + public static final boolean IS_20_22_OR_GREATER = isVersionOrGreater("20.22.00"); } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ButtonsFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ButtonsFilter.java index 3ac41318c..7512db706 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ButtonsFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ButtonsFilter.java @@ -1,5 +1,6 @@ package app.revanced.extension.youtube.patches.components; +import app.revanced.extension.youtube.patches.VersionCheckPatch; import app.revanced.extension.youtube.settings.Settings; @SuppressWarnings("unused") @@ -34,7 +35,6 @@ final class ButtonsFilter extends Filter { addPathCallbacks( likeSubscribeGlow, - bufferFilterPathGroup, new StringFilterGroup( Settings.HIDE_LIKE_DISLIKE_BUTTON, "|segmented_like_dislike_button" @@ -53,6 +53,12 @@ final class ButtonsFilter extends Filter { ) ); + // FIXME: 20.22+ filtering of the action buttons doesn't work because + // the buffer is the same for all buttons. + if (!VersionCheckPatch.IS_20_22_OR_GREATER) { + addPathCallbacks(bufferFilterPathGroup); + } + bufferButtonsGroupList.addAll( new ByteArrayFilterGroup( Settings.HIDE_REPORT_BUTTON, @@ -78,12 +84,6 @@ final class ButtonsFilter extends Filter { Settings.HIDE_STOP_ADS_BUTTON, "yt_outline_slash_circle_left" ), - // Check for clip button both here and using a path filter, - // as there's a chance the path is a generic action button and won't contain 'clip_button' - new ByteArrayFilterGroup( - Settings.HIDE_CLIP_BUTTON, - "yt_outline_scissors" - ), new ByteArrayFilterGroup( Settings.HIDE_HYPE_BUTTON, "yt_outline_star_shooting" @@ -96,11 +96,13 @@ final class ButtonsFilter extends Filter { } private boolean isEveryFilterGroupEnabled() { - for (var group : pathCallbacks) + for (var group : pathCallbacks) { if (!group.isEnabled()) return false; + } - for (var group : bufferButtonsGroupList) + for (var group : bufferButtonsGroupList) { if (!group.isEnabled()) return false; + } return true; } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java index 3635f25a8..c73bab074 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LayoutComponentsFilter.java @@ -1,5 +1,6 @@ package app.revanced.extension.youtube.patches.components; +import static app.revanced.extension.youtube.patches.VersionCheckPatch.IS_20_21_OR_GREATER; import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton; import android.graphics.drawable.Drawable; @@ -365,14 +366,16 @@ public final class LayoutComponentsFilter extends Filter { * Injection point. * Called from a different place then the other filters. */ - public static boolean filterMixPlaylists(Object conversionContext, @Nullable final byte[] bytes) { + public static boolean filterMixPlaylists(Object conversionContext, @Nullable byte[] buffer) { + // Edit: This hook may no longer be needed, and mix playlist filtering + // might be possible using the existing litho filters. try { if (!Settings.HIDE_MIX_PLAYLISTS.get()) { return false; } - if (bytes == null) { - Logger.printDebug(() -> "bytes is null"); + if (buffer == null) { + Logger.printDebug(() -> "buffer is null"); return false; } @@ -382,11 +385,11 @@ public final class LayoutComponentsFilter extends Filter { } // Prevent hiding the description of some videos accidentally. - if (mixPlaylistsExceptions2.check(bytes).isFiltered()) { + if (mixPlaylistsExceptions2.check(buffer).isFiltered()) { return false; } - if (mixPlaylists.check(bytes).isFiltered()) { + if (mixPlaylists.check(buffer).isFiltered()) { Logger.printDebug(() -> "Filtered mix playlist"); return true; } @@ -443,11 +446,23 @@ public final class LayoutComponentsFilter extends Filter { : height; } + private static final boolean HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS_ENABLED + = Settings.HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS.get(); + /** * Injection point. */ public static void hideInRelatedVideos(View chipView) { - Utils.hideViewBy0dpUnderCondition(Settings.HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS, chipView); + // Cannot use 0dp hide with later targets, otherwise the suggested videos + // can be shown in full screen mode. + // This behavior may also be present in earlier app targets. + if (IS_20_21_OR_GREATER) { + // FIXME: The filter bar is still briefly shown when dragging the suggested videos + // below the video player. + Utils.hideViewUnderCondition(HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS_ENABLED, chipView); + } else { + Utils.hideViewBy0dpUnderCondition(HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS_ENABLED, chipView); + } } private static final boolean HIDE_DOODLES_ENABLED = Settings.HIDE_DOODLES.get(); @@ -472,7 +487,9 @@ public final class LayoutComponentsFilter extends Filter { && NavigationBar.isSearchBarActive() // Search bar can be active but behind the player. && !PlayerType.getCurrent().isMaximizedOrFullscreen()) { - Utils.hideViewByLayoutParams(view); + // FIXME: "Show more" button is visible hidden, + // but an empty space remains that can be clicked. + Utils.hideViewBy0dp(view); } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java index e2ed04e63..619651cf0 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java @@ -4,11 +4,16 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Collections; import java.util.List; +import java.util.Map; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.youtube.StringTrieSearch; +import app.revanced.extension.youtube.patches.VersionCheckPatch; import app.revanced.extension.youtube.settings.Settings; @SuppressWarnings("unused") @@ -73,6 +78,15 @@ public final class LithoFilterPatch { } } + /** + * Placeholder for actual filters. + */ + private static final class DummyFilter extends Filter { } + + private static final Filter[] filters = new Filter[] { + new DummyFilter() // Replaced during patching, do not touch. + }; + /** * Litho layout fixed thread pool size override. *

@@ -90,25 +104,46 @@ public final class LithoFilterPatch { private static final int LITHO_LAYOUT_THREAD_POOL_SIZE = 1; /** - * Placeholder for actual filters. + * 20.22+ cannot use the thread buffer, because frequently the buffer is not correct, + * especially for components that are recreated such as dragging off screen then back on screen. + * Instead, parse the identifier found near the start of the buffer and use that to + * identify the correct buffer to use when filtering. */ - private static final class DummyFilter extends Filter { } + private static final boolean EXTRACT_IDENTIFIER_FROM_BUFFER = VersionCheckPatch.IS_20_22_OR_GREATER; - private static final Filter[] filters = new Filter[] { - new DummyFilter() // Replaced patching, do not touch. - }; + /** + * Turns on additional logging, used for development purposes only. + */ + public static final boolean DEBUG_EXTRACT_IDENTIFIER_FROM_BUFFER = false; - private static final StringTrieSearch pathSearchTree = new StringTrieSearch(); - private static final StringTrieSearch identifierSearchTree = new StringTrieSearch(); + private static final String EML_STRING = ".eml"; + private static final byte[] EML_STRING_BYTES = EML_STRING.getBytes(StandardCharsets.US_ASCII); private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; /** * Because litho filtering is multi-threaded and the buffer is passed in from a different injection point, * the buffer is saved to a ThreadLocal so each calling thread does not interfere with other threads. + * Used for 20.21 and lower. */ private static final ThreadLocal bufferThreadLocal = new ThreadLocal<>(); + /** + * Identifier to protocol buffer mapping. Only used for 20.22+. + * Thread local is needed because filtering is multi-threaded and each thread can load + * a different component with the same identifier. + */ + private static final ThreadLocal> identifierToBufferThread = new ThreadLocal<>(); + + /** + * Global shared buffer. Used only if the buffer is not found in the ThreadLocal. + */ + private static final Map identifierToBufferGlobal + = Collections.synchronizedMap(createIdentifierToBufferMap()); + + private static final StringTrieSearch pathSearchTree = new StringTrieSearch(); + private static final StringTrieSearch identifierSearchTree = new StringTrieSearch(); + static { for (Filter filter : filters) { filterUsingCallbacks(identifierSearchTree, filter, @@ -160,16 +195,107 @@ public final class LithoFilterPatch { } } + private static Map createIdentifierToBufferMap() { + // It's unclear how many items should be cached. This is a guess. + return Utils.createSizeRestrictedMap(100); + } + + /** + * Helper function that differs from {@link Character#isDigit(char)} + * as this only matches ascii and not unicode numbers. + */ + private static boolean isAsciiNumber(byte character) { + return '0' <= character && character <= '9'; + } + + private static boolean isAsciiLowerCaseLetter(byte character) { + return 'a' <= character && character <= 'z'; + } + /** * Injection point. Called off the main thread. * Targets 20.22+ */ public static void setProtoBuffer(byte[] buffer) { - // Set the buffer to a thread local. The buffer will remain in memory, even after the call to #filter completes. - // This is intentional, as it appears the buffer can be set once and then filtered multiple times. - // The buffer will be cleared from memory after a new buffer is set by the same thread, - // or when the calling thread eventually dies. - bufferThreadLocal.set(buffer); + if (DEBUG_EXTRACT_IDENTIFIER_FROM_BUFFER) { + StringBuilder builder = new StringBuilder(); + LithoFilterParameters.findAsciiStrings(builder, buffer); + Logger.printDebug(() -> "New buffer: " + builder); + } + + // Could use Boyer-Moore-Horspool since the string is ASCII and has a limited number of + // unique characters, but it seems to be slower since the extra overhead of checking the + // bad character array negates any performance gain of skipping a few extra subsearches. + int emlIndex = -1; + final int emlStringLength = EML_STRING_BYTES.length; + for (int i = 0, lastStartIndex = buffer.length - emlStringLength; i <= lastStartIndex; i++) { + boolean match = true; + for (int j = 0; j < emlStringLength; j++) { + if (buffer[i + j] != EML_STRING_BYTES[j]) { + match = false; + break; + } + } + if (match) { + emlIndex = i; + break; + } + } + + if (emlIndex < 0) { + // Buffer is not used for creating a new litho component. + return; + } + + int startIndex = emlIndex - 1; + while (startIndex > 0) { + final byte character = buffer[startIndex]; + int startIndexFinal = startIndex; + if (isAsciiNumber(character) || isAsciiLowerCaseLetter(character) || character == '_') { + // Valid character for the first path element. + startIndex--; + } else { + startIndex++; + break; + } + } + + // Strip away any numbers on the start of the identifier, which can + // be from random data in the buffer before the identifier starts. + while (true) { + final byte character = buffer[startIndex]; + if (isAsciiNumber(character)) { + startIndex++; + } else { + break; + } + } + + // Find the pipe character after the identifier. + int endIndex = -1; + for (int i = emlIndex, length = buffer.length; i < length; i++) { + if (buffer[i] == '|') { + endIndex = i; + break; + } + } + if (endIndex < 0) { + Logger.printException(() -> "Could not find buffer identifier"); + return; + } + + String identifier = new String(buffer, startIndex, endIndex - startIndex, StandardCharsets.US_ASCII); + if (DEBUG_EXTRACT_IDENTIFIER_FROM_BUFFER) { + Logger.printDebug(() -> "Found buffer for identifier: " + identifier); + } + identifierToBufferGlobal.put(identifier, buffer); + + Map map = identifierToBufferThread.get(); + if (map == null) { + map = createIdentifierToBufferMap(); + identifierToBufferThread.set(map); + } + map.put(identifier, buffer); } /** @@ -177,46 +303,70 @@ public final class LithoFilterPatch { * Targets 20.21 and lower. */ public static void setProtoBuffer(@Nullable ByteBuffer buffer) { - // Set the buffer to a thread local. The buffer will remain in memory, even after the call to #filter completes. - // This is intentional, as it appears the buffer can be set once and then filtered multiple times. - // The buffer will be cleared from memory after a new buffer is set by the same thread, - // or when the calling thread eventually dies. if (buffer == null || !buffer.hasArray()) { // It appears the buffer can be cleared out just before the call to #filter() // Ignore this null value and retain the last buffer that was set. Logger.printDebug(() -> "Ignoring null or empty buffer: " + buffer); } else { - setProtoBuffer(buffer.array()); + // Set the buffer to a thread local. The buffer will remain in memory, even after the call to #filter completes. + // This is intentional, as it appears the buffer can be set once and then filtered multiple times. + // The buffer will be cleared from memory after a new buffer is set by the same thread, + // or when the calling thread eventually dies. + bufferThreadLocal.set(buffer.array()); } } /** * Injection point. */ - public static boolean isFiltered(String lithoIdentifier, StringBuilder pathBuilder) { + public static boolean isFiltered(String identifier, StringBuilder pathBuilder) { try { - if (lithoIdentifier.isEmpty() && pathBuilder.length() == 0) { + if (identifier.isEmpty() || pathBuilder.length() == 0) { return false; } - byte[] buffer = bufferThreadLocal.get(); + byte[] buffer = null; + if (EXTRACT_IDENTIFIER_FROM_BUFFER) { + final int pipeIndex = identifier.indexOf('|'); + if (pipeIndex >= 0) { + // If the identifier contains no pipe, then it's not an ".eml" identifier + // and the buffer is not uniquely identified. Typically this only happens + // for subcomponents where buffer filtering is not used. + String identifierKey = identifier.substring(0, pipeIndex); + + var map = identifierToBufferThread.get(); + if (map != null) { + buffer = map.get(identifierKey); + } + + if (buffer == null) { + // Buffer for thread local not found. Use the last buffer found from any thread. + buffer = identifierToBufferGlobal.get(identifierKey); + + if (DEBUG_EXTRACT_IDENTIFIER_FROM_BUFFER && buffer == null) { + // No buffer is found for some components, such as + // shorts_lockup_cell.eml on channel profiles. + // For now, just ignore this and filter without a buffer. + Logger.printException(() -> "Could not find global buffer for identifier: " + identifier); + } + } + } + } else { + buffer = bufferThreadLocal.get(); + } + // Potentially the buffer may have been null or never set up until now. - // Use an empty buffer so the litho id/path filters still work correctly. + // Use an empty buffer so the litho id/path filters that do not use a buffer still work. if (buffer == null) { buffer = EMPTY_BYTE_ARRAY; } - LithoFilterParameters parameter = new LithoFilterParameters( - lithoIdentifier, pathBuilder.toString(), buffer); + String path = pathBuilder.toString(); + LithoFilterParameters parameter = new LithoFilterParameters(identifier, path, buffer); Logger.printDebug(() -> "Searching " + parameter); - if (identifierSearchTree.matches(parameter.identifier, parameter)) { - return true; - } - - if (pathSearchTree.matches(parameter.path, parameter)) { - return true; - } + return identifierSearchTree.matches(identifier, parameter) + || pathSearchTree.matches(path, parameter); } catch (Exception ex) { Logger.printException(() -> "isFiltered failure", ex); } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter.java index b82cb5f56..5a2e97aff 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilter.java @@ -4,15 +4,15 @@ import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; +import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.Utils; +import app.revanced.extension.youtube.TrieSearch; import app.revanced.extension.youtube.patches.ReturnYouTubeDislikePatch; import app.revanced.extension.youtube.patches.VideoInformation; import app.revanced.extension.youtube.settings.Settings; -import app.revanced.extension.shared.Logger; -import app.revanced.extension.youtube.TrieSearch; /** * Searches for video id's in the proto buffer of Shorts dislike. @@ -33,18 +33,7 @@ public final class ReturnYouTubeDislikeFilter extends Filter { * Cannot use {@link LinkedHashSet} because it's missing #removeEldestEntry(). */ @GuardedBy("itself") - private static final Map lastVideoIds = new LinkedHashMap<>() { - /** - * Number of video id's to keep track of for searching thru the buffer. - * A minimum value of 3 should be sufficient, but check a few more just in case. - */ - private static final int NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK = 5; - - @Override - protected boolean removeEldestEntry(Entry eldest) { - return size() > NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK; - } - }; + private static final Map lastVideoIds = Utils.createSizeRestrictedMap(5); /** * Injection point. diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ShortsFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ShortsFilter.java index f4fae4d32..291577302 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ShortsFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/ShortsFilter.java @@ -11,6 +11,7 @@ import java.util.Arrays; import java.util.List; import app.revanced.extension.shared.Logger; +import app.revanced.extension.youtube.patches.VersionCheckPatch; import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.shared.NavigationBar; import app.revanced.extension.youtube.shared.PlayerType; @@ -202,7 +203,11 @@ public final class ShortsFilter extends Filter { videoActionButton = new StringFilterGroup( null, - // Can be simply 'button.eml', 'shorts_video_action_button.eml' or 'reel_action_button.eml' + // Can be any of: + // button.eml + // shorts_video_action_button.eml + // reel_action_button.eml + // reel_pivot_button.eml "button.eml" ); @@ -213,31 +218,37 @@ public final class ShortsFilter extends Filter { addPathCallbacks( shortsCompactFeedVideo, joinButton, subscribeButton, paidPromotionButton, - shortsActionBar, suggestedAction, pausedOverlayButtons, channelBar, + suggestedAction, pausedOverlayButtons, channelBar, fullVideoLinkLabel, videoTitle, useSoundButton, reelSoundMetadata, soundButton, infoPanel, stickers, likeFountain, likeButton, dislikeButton ); - // - // All other action buttons. - // - videoActionButtonBuffer.addAll( - new ByteArrayFilterGroup( - Settings.HIDE_SHORTS_COMMENTS_BUTTON, - "reel_comment_button", - "youtube_shorts_comment_outline" - ), - new ByteArrayFilterGroup( - Settings.HIDE_SHORTS_SHARE_BUTTON, - "reel_share_button", - "youtube_shorts_share_outline" - ), - new ByteArrayFilterGroup( - Settings.HIDE_SHORTS_REMIX_BUTTON, - "reel_remix_button", - "youtube_shorts_remix_outline" - ) - ); + // FIXME: The Shorts buffer is very different with 20.22+ and if any of these filters + // are enabled then all Shorts player vertical buttons are hidden. + if (!VersionCheckPatch.IS_20_22_OR_GREATER) { + addPathCallbacks(shortsActionBar); + + // + // All other action buttons. + // + videoActionButtonBuffer.addAll( + new ByteArrayFilterGroup( + Settings.HIDE_SHORTS_COMMENTS_BUTTON, + "reel_comment_button", + "youtube_shorts_comment_outline" + ), + new ByteArrayFilterGroup( + Settings.HIDE_SHORTS_SHARE_BUTTON, + "reel_share_button", + "youtube_shorts_share_outline" + ), + new ByteArrayFilterGroup( + Settings.HIDE_SHORTS_REMIX_BUTTON, + "reel_remix_button", + "youtube_shorts_remix_outline" + ) + ); + } // // Suggested actions. diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/quality/RememberVideoQualityPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/quality/RememberVideoQualityPatch.java index 0ead14314..1f726c2a5 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/quality/RememberVideoQualityPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/playback/quality/RememberVideoQualityPatch.java @@ -21,7 +21,6 @@ public class RememberVideoQualityPatch { private static final IntegerSetting shortsQualityWifi = Settings.SHORTS_QUALITY_DEFAULT_WIFI; private static final IntegerSetting shortsQualityMobile = Settings.SHORTS_QUALITY_DEFAULT_MOBILE; - public static boolean shouldRememberVideoQuality() { BooleanSetting preference = ShortsPlayerState.isOpen() ? Settings.REMEMBER_SHORTS_QUALITY_LAST_SELECTED diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/SeekbarColorPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/SeekbarColorPatch.java index 965b16364..1cffc4948 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/SeekbarColorPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/theme/SeekbarColorPatch.java @@ -19,6 +19,7 @@ import java.util.Locale; import java.util.Scanner; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.youtube.settings.Settings; @@ -152,8 +153,8 @@ public final class SeekbarColorPatch { Logger.printDebug(() -> "Using splash seekbar style: " + seekbarStyle); final int styleIdentifierDefault = Utils.getResourceIdentifier( - seekbarStyle, - "style" + ResourceType.STYLE, + seekbarStyle ); if (styleIdentifierDefault == 0) { throw new RuntimeException("Seekbar style not found: " + seekbarStyle); diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/returnyoutubedislike/ReturnYouTubeDislike.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/returnyoutubedislike/ReturnYouTubeDislike.java index ade422260..6b9681295 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/returnyoutubedislike/ReturnYouTubeDislike.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/returnyoutubedislike/ReturnYouTubeDislike.java @@ -258,7 +258,8 @@ public class ReturnYouTubeDislike { // middle separator String middleSeparatorString = compactLayout ? " " + MIDDLE_SEPARATOR_CHARACTER + " " - : " \u2009" + MIDDLE_SEPARATOR_CHARACTER + "\u2009 "; // u2009 = 'narrow space' character + : " \u2009\u2009" + MIDDLE_SEPARATOR_CHARACTER + "\u2009\u2009 "; // u2009 = 'narrow space' + final int shapeInsertionIndex = middleSeparatorString.length() / 2; Spannable middleSeparatorSpan = new SpannableString(middleSeparatorString); ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape()); diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/LicenseActivityHook.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/LicenseActivityHook.java index 24d3a4f42..de9f50dba 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/LicenseActivityHook.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/LicenseActivityHook.java @@ -13,6 +13,7 @@ import android.widget.TextView; import android.widget.Toolbar; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.AppLanguage; import app.revanced.extension.shared.settings.BaseSettings; @@ -87,7 +88,7 @@ public class LicenseActivityHook extends Activity { setActivityTheme(licenseActivity); ReVancedPreferenceFragment.setNavigationBarColor(licenseActivity.getWindow()); licenseActivity.setContentView(getResourceIdentifier( - "revanced_settings_with_toolbar", "layout")); + ResourceType.LAYOUT, "revanced_settings_with_toolbar")); // Sanity check. String dataString = licenseActivity.getIntent().getDataString(); @@ -102,7 +103,7 @@ public class LicenseActivityHook extends Activity { //noinspection deprecation licenseActivity.getFragmentManager() .beginTransaction() - .replace(getResourceIdentifier("revanced_settings_fragments", "id"), fragment) + .replace(getResourceIdentifier(ResourceType.ID, "revanced_settings_fragments"), fragment) .commit(); } catch (Exception ex) { Logger.printException(() -> "initialize failure", ex); @@ -114,7 +115,7 @@ public class LicenseActivityHook extends Activity { // Replace dummy placeholder toolbar. // This is required to fix submenu title alignment issue with Android ASOP 15+ ViewGroup toolBarParent = activity.findViewById( - getResourceIdentifier("revanced_toolbar_parent", "id")); + getResourceIdentifier(ResourceType.ID, "revanced_toolbar_parent")); ViewGroup dummyToolbar = Utils.getChildViewByResourceName(toolBarParent, "revanced_toolbar"); toolbarLayoutParams = dummyToolbar.getLayoutParams(); toolBarParent.removeView(dummyToolbar); @@ -122,7 +123,7 @@ public class LicenseActivityHook extends Activity { Toolbar toolbar = new Toolbar(toolBarParent.getContext()); toolbar.setBackgroundColor(getToolbarBackgroundColor()); toolbar.setNavigationIcon(ReVancedPreferenceFragment.getBackButtonDrawable()); - toolbar.setTitle(getResourceIdentifier("revanced_settings_title", "string")); + toolbar.setTitle(getResourceIdentifier(ResourceType.STRING, "revanced_settings_title")); final int margin = Utils.dipToPixels(16); toolbar.setTitleMarginStart(margin); @@ -147,7 +148,7 @@ public class LicenseActivityHook extends Activity { final var theme = Utils.isDarkModeEnabled() ? "Theme.YouTube.Settings.Dark" : "Theme.YouTube.Settings"; - activity.setTheme(getResourceIdentifier(theme, "style")); + activity.setTheme(getResourceIdentifier(ResourceType.STYLE, theme)); } public static int getToolbarBackgroundColor() { diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/SearchViewController.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/SearchViewController.java index 10be641f7..844294d15 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/SearchViewController.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/SearchViewController.java @@ -30,6 +30,7 @@ import java.util.LinkedList; import java.util.List; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.AppLanguage; import app.revanced.extension.shared.settings.BaseSettings; @@ -68,7 +69,7 @@ public class SearchViewController { /** * Creates a background drawable for suggestion items with rounded corners. */ - private static GradientDrawable createSuggestionBackgroundDrawable(Context context) { + private static GradientDrawable createSuggestionBackgroundDrawable() { GradientDrawable background = new GradientDrawable(); background.setShape(GradientDrawable.RECTANGLE); background.setColor(getSearchViewBackground()); @@ -109,9 +110,11 @@ public class SearchViewController { // Retrieve SearchView and container from XML. searchView = activity.findViewById(getResourceIdentifier( - "revanced_search_view", "id")); + ResourceType.ID, + "revanced_search_view")); searchContainer = activity.findViewById(getResourceIdentifier( - "revanced_search_view_container", "id")); + ResourceType.ID, + "revanced_search_view_container")); // Initialize AutoCompleteTextView. autoCompleteTextView = searchView.findViewById( @@ -178,8 +181,8 @@ public class SearchViewController { }); // Set menu and search icon. - final int actionSearchId = getResourceIdentifier("action_search", "id"); - toolbar.inflateMenu(getResourceIdentifier("revanced_search_menu", "menu")); + final int actionSearchId = getResourceIdentifier(ResourceType.ID, "action_search"); + toolbar.inflateMenu(getResourceIdentifier(ResourceType.MENU, "revanced_search_menu")); MenuItem searchItem = toolbar.getMenu().findItem(actionSearchId); // Set menu item click listener. @@ -307,7 +310,8 @@ public class SearchViewController { private void openSearch() { isSearchActive = true; toolbar.getMenu().findItem(getResourceIdentifier( - "action_search", "id")).setVisible(false); + ResourceType.ID, + "action_search")).setVisible(false); toolbar.setTitle(""); searchContainer.setVisibility(View.VISIBLE); searchView.requestFocus(); @@ -332,7 +336,8 @@ public class SearchViewController { public void closeSearch() { isSearchActive = false; toolbar.getMenu().findItem(getResourceIdentifier( - "action_search", "id")).setVisible(true); + ResourceType.ID, + "action_search")).setVisible(true); toolbar.setTitle(originalTitle); searchContainer.setVisibility(View.GONE); searchView.setQuery("", false); @@ -368,16 +373,18 @@ public class SearchViewController { public View getView(int position, View convertView, @NonNull android.view.ViewGroup parent) { if (convertView == null) { convertView = LinearLayout.inflate(getContext(), getResourceIdentifier( - "revanced_search_suggestion_item", "layout"), null); + ResourceType.LAYOUT, + "revanced_search_suggestion_item"), null); } // Apply rounded corners programmatically. - convertView.setBackground(createSuggestionBackgroundDrawable(getContext())); + convertView.setBackground(createSuggestionBackgroundDrawable()); String query = getItem(position); // Set query text. TextView textView = convertView.findViewById(getResourceIdentifier( - "suggestion_text", "id")); + ResourceType.ID, + "suggestion_text")); if (textView != null) { textView.setText(query); } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 2c089bb69..ab1414b8e 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -13,6 +13,7 @@ import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.Change import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.StartPage; import static app.revanced.extension.youtube.patches.ExitFullscreenPatch.FullscreenMode; import static app.revanced.extension.youtube.patches.ForceOriginalAudioPatch.ForceOriginalAudioAvailability; +import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHideOverlayButtonsAvailability; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MINIMAL; @@ -46,7 +47,6 @@ import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrow import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailStillTime; -import app.revanced.extension.youtube.patches.MiniplayerPatch; import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings; import app.revanced.extension.youtube.swipecontrols.SwipeControlsConfigurationProvider.SwipeOverlayStyle; @@ -182,8 +182,8 @@ public class Settings extends BaseSettings { public static final BooleanSetting MINIPLAYER_DOUBLE_TAP_ACTION = new BooleanSetting("revanced_miniplayer_double_tap_action", TRUE, true, MINIPLAYER_ANY_MODERN); public static final BooleanSetting MINIPLAYER_DRAG_AND_DROP = new BooleanSetting("revanced_miniplayer_drag_and_drop", TRUE, true, MINIPLAYER_ANY_MODERN); public static final BooleanSetting MINIPLAYER_HORIZONTAL_DRAG = new BooleanSetting("revanced_miniplayer_horizontal_drag", FALSE, true, new MiniplayerHorizontalDragAvailability()); - public static final BooleanSetting MINIPLAYER_HIDE_OVERLAY_BUTTONS = new BooleanSetting("revanced_miniplayer_hide_overlay_buttons", FALSE, true, new MiniplayerPatch.MiniplayerHideOverlayButtonsAvailability()); - public static final BooleanSetting MINIPLAYER_HIDE_SUBTEXT = new BooleanSetting("revanced_miniplayer_hide_subtext", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1, MODERN_3)); + public static final BooleanSetting MINIPLAYER_HIDE_OVERLAY_BUTTONS = new BooleanSetting("revanced_miniplayer_hide_overlay_buttons", FALSE, true, new MiniplayerHideOverlayButtonsAvailability()); + public static final BooleanSetting MINIPLAYER_HIDE_SUBTEXT = new BooleanSetting("revanced_miniplayer_hide_subtext", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1, MODERN_3, MODERN_4)); public static final BooleanSetting MINIPLAYER_HIDE_REWIND_FORWARD = new BooleanSetting("revanced_miniplayer_hide_rewind_forward", TRUE, true, MINIPLAYER_TYPE.availability(MODERN_1)); public static final BooleanSetting MINIPLAYER_ROUNDED_CORNERS = new BooleanSetting("revanced_miniplayer_rounded_corners", TRUE, true, MINIPLAYER_ANY_MODERN); public static final IntegerSetting MINIPLAYER_WIDTH_DIP = new IntegerSetting("revanced_miniplayer_width_dip", 192, true, MINIPLAYER_ANY_MODERN); @@ -282,6 +282,7 @@ public class Settings extends BaseSettings { public static final BooleanSetting HIDE_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_hide_notifications_button", FALSE, true); public static final BooleanSetting SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_switch_create_with_notifications_button", TRUE, true, "revanced_switch_create_with_notifications_button_user_dialog_message"); + public static final BooleanSetting NAVIGATION_BAR_ANIMATIONS = new BooleanSetting("revanced_navigation_bar_animations", FALSE); public static final BooleanSetting DISABLE_TRANSLUCENT_STATUS_BAR = new BooleanSetting("revanced_disable_translucent_status_bar", FALSE, true, "revanced_disable_translucent_status_bar_user_dialog_message"); public static final BooleanSetting DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT = new BooleanSetting("revanced_disable_translucent_navigation_bar_light", FALSE, true); @@ -333,6 +334,7 @@ public class Settings extends BaseSettings { public static final BooleanSetting DISABLE_PRECISE_SEEKING_GESTURE = new BooleanSetting("revanced_disable_precise_seeking_gesture", FALSE); public static final BooleanSetting HIDE_SEEKBAR = new BooleanSetting("revanced_hide_seekbar", FALSE, true); public static final BooleanSetting HIDE_SEEKBAR_THUMBNAIL = new BooleanSetting("revanced_hide_seekbar_thumbnail", FALSE, true); + public static final BooleanSetting FULLSCREEN_LARGE_SEEKBAR = new BooleanSetting("revanced_fullscreen_large_seekbar", FALSE); public static final BooleanSetting HIDE_TIMESTAMP = new BooleanSetting("revanced_hide_timestamp", FALSE); public static final BooleanSetting RESTORE_OLD_SEEKBAR_THUMBNAILS = new BooleanSetting("revanced_restore_old_seekbar_thumbnails", TRUE); public static final BooleanSetting SEEKBAR_TAPPING = new BooleanSetting("revanced_seekbar_tapping", FALSE); diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ExternalDownloaderPreference.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ExternalDownloaderPreference.java index 0165e1376..5e25ae10c 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ExternalDownloaderPreference.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ExternalDownloaderPreference.java @@ -34,6 +34,7 @@ import java.util.Objects; import java.util.function.Function; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.preference.CustomDialogListPreference; import app.revanced.extension.youtube.settings.Settings; @@ -210,7 +211,7 @@ public class ExternalDownloaderPreference extends CustomDialogListPreference { final boolean usingCustomDownloader = Downloader.findByPackageName(packageName) == null; adapter = new CustomDialogListPreference.ListPreferenceArrayAdapter( context, - Utils.getResourceIdentifier("revanced_custom_list_item_checked", "layout"), + Utils.getResourceIdentifier(ResourceType.LAYOUT, "revanced_custom_list_item_checked"), getEntries(), getEntryValues(), usingCustomDownloader diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedPreferenceFragment.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedPreferenceFragment.java index c4cb42313..95a594849 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedPreferenceFragment.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ReVancedPreferenceFragment.java @@ -38,6 +38,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment; @@ -72,7 +73,9 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment { @SuppressLint("UseCompatLoadingForDrawables") public static Drawable getBackButtonDrawable() { - final int backButtonResource = getResourceIdentifier("revanced_settings_toolbar_arrow_left", "drawable"); + final int backButtonResource = getResourceIdentifier( + ResourceType.DRAWABLE, + "revanced_settings_toolbar_arrow_left"); Drawable drawable = Utils.getContext().getResources().getDrawable(backButtonResource); drawable.setTint(Utils.getAppForegroundColor()); return drawable; @@ -217,8 +220,11 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment { noResultsPreference.setSelectable(false); // Set icon for the placeholder preference. noResultsPreference.setLayoutResource(getResourceIdentifier( - "revanced_preference_with_icon_no_search_result", "layout")); - noResultsPreference.setIcon(getResourceIdentifier("revanced_settings_search_icon", "drawable")); + ResourceType.LAYOUT, + "revanced_preference_with_icon_no_search_result")); + noResultsPreference.setIcon(getResourceIdentifier( + ResourceType.DRAWABLE, + "revanced_settings_search_icon")); preferenceScreen.addPreference(noResultsPreference); } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/NavigationBar.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/NavigationBar.java index 17a509f00..a0194f0dc 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/NavigationBar.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/NavigationBar.java @@ -19,6 +19,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.youtube.settings.Settings; @@ -282,7 +283,8 @@ public final class NavigationBar { * the what would be the filled cairo icon. */ private static final int fillBellCairoBlack = Utils.getResourceIdentifier( - "yt_fill_bell_black_24", "drawable"); + ResourceType.DRAWABLE, + "yt_fill_bell_black_24"); /** * Injection point. diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibilityObserver.kt b/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibilityObserver.kt index 26745755d..f5c51c5f3 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibilityObserver.kt +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/PlayerControlsVisibilityObserver.kt @@ -3,6 +3,7 @@ package app.revanced.extension.youtube.shared import android.app.Activity import android.view.View import android.view.ViewGroup +import app.revanced.extension.shared.ResourceType import app.revanced.extension.shared.Utils import java.lang.ref.WeakReference @@ -19,13 +20,13 @@ class PlayerControlsVisibilityObserverImpl( * id of the direct parent of controls_layout, R.id.youtube_controls_overlay */ private val controlsLayoutParentId = - Utils.getResourceIdentifier(activity, "youtube_controls_overlay", "id") + Utils.getResourceIdentifier(activity, ResourceType.ID, "youtube_controls_overlay") /** * id of R.id.controls_layout */ private val controlsLayoutId = - Utils.getResourceIdentifier(activity, "controls_layout", "id") + Utils.getResourceIdentifier(activity, ResourceType.ID, "controls_layout") /** * reference to the controls layout view diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/PlayerType.kt b/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/PlayerType.kt index 147abc13f..0b97b05c6 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/PlayerType.kt +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/shared/PlayerType.kt @@ -2,7 +2,6 @@ package app.revanced.extension.youtube.shared import app.revanced.extension.shared.Logger import app.revanced.extension.youtube.Event -import app.revanced.extension.youtube.patches.VideoInformation /** * Regular player type. diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SegmentPlaybackController.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SegmentPlaybackController.java index 570496a07..d3df3f230 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SegmentPlaybackController.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SegmentPlaybackController.java @@ -26,7 +26,6 @@ import android.widget.TextView; import androidx.annotation.Nullable; import java.lang.ref.WeakReference; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -151,9 +150,9 @@ public class SegmentPlaybackController { private static long skipSegmentButtonEndTime; @Nullable private static String timeWithoutSegments; - private static int sponsorBarAbsoluteLeft; - private static int sponsorAbsoluteBarRight; - private static int sponsorBarThickness; + private static int seekbarAbsoluteLeft; + private static int seekbarAbsoluteRight; + private static int seekbarThickness; @Nullable private static SponsorSegment lastSegmentSkipped; @@ -923,31 +922,13 @@ public class SegmentPlaybackController { * injection point. */ @SuppressWarnings("unused") - public static void setSponsorBarRect(Object self) { - try { - Field field = self.getClass().getDeclaredField("replaceMeWithsetSponsorBarRect"); - field.setAccessible(true); - Rect rect = (Rect) Objects.requireNonNull(field.get(self)); - setSponsorBarAbsoluteLeft(rect); - setSponsorBarAbsoluteRight(rect); - } catch (Exception ex) { - Logger.printException(() -> "setSponsorBarRect failure", ex); - } - } - - private static void setSponsorBarAbsoluteLeft(Rect rect) { - final int left = rect.left; - if (sponsorBarAbsoluteLeft != left) { - Logger.printDebug(() -> "setSponsorBarAbsoluteLeft: " + left); - sponsorBarAbsoluteLeft = left; - } - } - - private static void setSponsorBarAbsoluteRight(Rect rect) { - final int right = rect.right; - if (sponsorAbsoluteBarRight != right) { - Logger.printDebug(() -> "setSponsorBarAbsoluteRight: " + right); - sponsorAbsoluteBarRight = right; + public static void setSeekbarRectangle(Rect seekbarRect) { + final int left = seekbarRect.left; + final int right = seekbarRect.right; + if (seekbarAbsoluteLeft != left || seekbarAbsoluteRight != right) { + Logger.printDebug(() -> "setSeekbarRectangle left: " + left + " right: " + right); + seekbarAbsoluteLeft = left; + seekbarAbsoluteRight = right; } } @@ -955,8 +936,8 @@ public class SegmentPlaybackController { * injection point. */ @SuppressWarnings("unused") - public static void setSponsorBarThickness(int thickness) { - sponsorBarThickness = thickness; + public static void setSeekbarThickness(int thickness) { + seekbarThickness = thickness; } /** @@ -966,8 +947,7 @@ public class SegmentPlaybackController { public static String appendTimeWithoutSegments(String totalTime) { try { if (Settings.SB_ENABLED.get() && Settings.SB_VIDEO_LENGTH_WITHOUT_SEGMENTS.get() - && !TextUtils.isEmpty(totalTime) && !TextUtils.isEmpty(timeWithoutSegments) - && !isAdProgressTextVisible()) { + && !TextUtils.isEmpty(totalTime) && !TextUtils.isEmpty(timeWithoutSegments)) { // Force LTR layout, to match the same LTR video time/length layout YouTube uses for all languages return "\u202D" + totalTime + timeWithoutSegments; // u202D = left to right override } @@ -995,6 +975,7 @@ public class SegmentPlaybackController { continue; } foundNonhighlightSegments = true; + long start = segment.start; final long end = segment.end; // To prevent nested segments from incorrectly counting additional time, @@ -1026,17 +1007,17 @@ public class SegmentPlaybackController { * Injection point. */ @SuppressWarnings("unused") - public static void drawSponsorTimeBars(final Canvas canvas, final float posY) { + public static void drawSegmentTimeBars(final Canvas canvas, final float posY) { try { - if (segments == null || isAdProgressTextVisible()) return; + if (segments == null) return; final long videoLength = VideoInformation.getVideoLength(); if (videoLength <= 0) return; - final int thicknessDiv2 = sponsorBarThickness / 2; // rounds down - final float top = posY - (sponsorBarThickness - thicknessDiv2); + final int thicknessDiv2 = seekbarThickness / 2; // Rounds down. + final float top = posY - (seekbarThickness - thicknessDiv2); final float bottom = posY + thicknessDiv2; - final float videoMillisecondsToPixels = (1f / videoLength) * (sponsorAbsoluteBarRight - sponsorBarAbsoluteLeft); - final float leftPadding = sponsorBarAbsoluteLeft; + final float videoMillisecondsToPixels = (1f / videoLength) * (seekbarAbsoluteRight - seekbarAbsoluteLeft); + final float leftPadding = seekbarAbsoluteLeft; for (SponsorSegment segment : segments) { final float left = leftPadding + segment.start * videoMillisecondsToPixels; diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategoryListPreference.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategoryListPreference.java index ee3c1c138..3da8cd5d5 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategoryListPreference.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategoryListPreference.java @@ -26,6 +26,7 @@ import java.util.Locale; import java.util.Objects; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.preference.ColorPickerPreference; import app.revanced.extension.shared.settings.preference.ColorPickerView; @@ -100,10 +101,10 @@ public class SegmentCategoryListPreference extends ListPreference { contentLayout.addView(radioGroup); // Inflate the color picker view. - View colorPickerContainer = LayoutInflater.from(context) - .inflate(getResourceIdentifier("revanced_color_picker", "layout"), null); + View colorPickerContainer = LayoutInflater.from(context).inflate( + getResourceIdentifier(ResourceType.LAYOUT, "revanced_color_picker"), null); dialogColorPickerView = colorPickerContainer.findViewById( - getResourceIdentifier("revanced_color_picker_view", "id")); + getResourceIdentifier(ResourceType.ID, "revanced_color_picker_view")); dialogColorPickerView.setColor(categoryColor); contentLayout.addView(colorPickerContainer); diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/CreateSegmentButton.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/CreateSegmentButton.java index 99dbf7e18..5ff999987 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/CreateSegmentButton.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/CreateSegmentButton.java @@ -59,6 +59,7 @@ public class CreateSegmentButton { private static boolean isButtonEnabled() { return Settings.SB_ENABLED.get() && Settings.SB_CREATE_NEW_SEGMENT.get() + && SegmentPlaybackController.videoHasSegments() && !SegmentPlaybackController.isAdProgressTextVisible(); } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/NewSegmentLayout.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/NewSegmentLayout.java index 0b0793388..175d49b94 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/NewSegmentLayout.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/NewSegmentLayout.java @@ -10,6 +10,7 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageButton; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.youtube.patches.VideoInformation; import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.sponsorblock.SponsorBlockUtils; @@ -45,7 +46,10 @@ public final class NewSegmentLayout extends FrameLayout { super(context, attributeSet, defStyleAttr, defStyleRes); LayoutInflater.from(context).inflate( - getResourceIdentifier(context, "revanced_sb_new_segment", "layout"), this, true + getResourceIdentifier(context, + ResourceType.LAYOUT, "revanced_sb_new_segment"), + this, + true ); initializeButton( @@ -104,7 +108,7 @@ public final class NewSegmentLayout extends FrameLayout { */ private void initializeButton(final Context context, final String resourceIdentifierName, final ButtonOnClickHandlerFunction handler, final String debugMessage) { - ImageButton button = findViewById(getResourceIdentifier(context, resourceIdentifierName, "id")); + ImageButton button = findViewById(getResourceIdentifier(context, ResourceType.ID, resourceIdentifierName)); // Add ripple effect RippleDrawable rippleDrawable = new RippleDrawable( diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/SkipSponsorButton.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/SkipSponsorButton.java index 6ca96cd37..17b388bb7 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/SkipSponsorButton.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/SkipSponsorButton.java @@ -20,6 +20,7 @@ import androidx.annotation.NonNull; import java.util.Objects; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController; import app.revanced.extension.youtube.sponsorblock.objects.SponsorSegment; @@ -56,9 +57,9 @@ public class SkipSponsorButton extends FrameLayout { public SkipSponsorButton(Context context, AttributeSet attributeSet, int defStyleAttr, int defStyleRes) { super(context, attributeSet, defStyleAttr, defStyleRes); - LayoutInflater.from(context).inflate(getResourceIdentifier(context, "revanced_sb_skip_sponsor_button", "layout"), this, true); // layout:skip_ad_button + LayoutInflater.from(context).inflate(getResourceIdentifier(context, ResourceType.LAYOUT, "revanced_sb_skip_sponsor_button"), this, true); // layout:skip_ad_button setMinimumHeight(getResourceDimensionPixelSize("ad_skip_ad_button_min_height")); // dimen:ad_skip_ad_button_min_height - skipSponsorBtnContainer = Objects.requireNonNull(findViewById(getResourceIdentifier(context, "revanced_sb_skip_sponsor_button_container", "id"))); // id:skip_ad_button_container + skipSponsorBtnContainer = Objects.requireNonNull(findViewById(getResourceIdentifier(context, ResourceType.ID, "revanced_sb_skip_sponsor_button_container"))); // id:skip_ad_button_container background = new Paint(); background.setColor(getResourceColor("skip_ad_button_background_color")); // color:skip_ad_button_background_color); @@ -69,7 +70,7 @@ public class SkipSponsorButton extends FrameLayout { border.setStrokeWidth(getResourceDimension("ad_skip_ad_button_border_width")); // dimen:ad_skip_ad_button_border_width); border.setStyle(Paint.Style.STROKE); - skipSponsorTextView = Objects.requireNonNull(findViewById(getResourceIdentifier(context, "revanced_sb_skip_sponsor_button_text", "id"))); // id:skip_ad_button_text; + skipSponsorTextView = Objects.requireNonNull(findViewById(getResourceIdentifier(context, ResourceType.ID, "revanced_sb_skip_sponsor_button_text"))); // id:skip_ad_button_text; defaultBottomMargin = getResourceDimensionPixelSize("skip_button_default_bottom_margin"); // dimen:skip_button_default_bottom_margin ctaBottomMargin = getResourceDimensionPixelSize("skip_button_cta_bottom_margin"); // dimen:skip_button_cta_bottom_margin diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/SponsorBlockViewController.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/SponsorBlockViewController.java index dd753934a..bcd1b8895 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/SponsorBlockViewController.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/SponsorBlockViewController.java @@ -15,6 +15,7 @@ import java.lang.ref.WeakReference; import java.util.Objects; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.youtube.shared.PlayerType; import app.revanced.extension.youtube.sponsorblock.objects.SponsorSegment; @@ -62,15 +63,17 @@ public class SponsorBlockViewController { Context context = Utils.getContext(); RelativeLayout layout = new RelativeLayout(context); - layout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT)); - LayoutInflater.from(context).inflate(getResourceIdentifier("revanced_sb_inline_sponsor_overlay", "layout"), layout); + layout.setLayoutParams(new RelativeLayout.LayoutParams( + RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); + LayoutInflater.from(context).inflate(getResourceIdentifier(ResourceType.LAYOUT, + "revanced_sb_inline_sponsor_overlay"), layout); inlineSponsorOverlayRef = new WeakReference<>(layout); viewGroup.addView(layout); viewGroup.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() { @Override public void onChildViewAdded(View parent, View child) { - // ensure SB buttons and controls are always on top, otherwise the endscreen cards can cover the skip button + // Ensure SB buttons and controls are always on top, otherwise the end-screen cards can cover the skip button. RelativeLayout layout = inlineSponsorOverlayRef.get(); if (layout != null) { layout.bringToFront(); @@ -83,13 +86,13 @@ public class SponsorBlockViewController { youtubeOverlaysLayoutRef = new WeakReference<>(viewGroup); skipHighlightButtonRef = new WeakReference<>(Objects.requireNonNull( - layout.findViewById(getResourceIdentifier("revanced_sb_skip_highlight_button", "id")))); + layout.findViewById(getResourceIdentifier(ResourceType.ID, "revanced_sb_skip_highlight_button")))); skipSponsorButtonRef = new WeakReference<>(Objects.requireNonNull( - layout.findViewById(getResourceIdentifier("revanced_sb_skip_sponsor_button", "id")))); + layout.findViewById(getResourceIdentifier(ResourceType.ID, "revanced_sb_skip_sponsor_button")))); NewSegmentLayout newSegmentLayout = Objects.requireNonNull( - layout.findViewById(getResourceIdentifier("revanced_sb_new_segment_view", "id"))); + layout.findViewById(getResourceIdentifier(ResourceType.ID, "revanced_sb_new_segment_view"))); newSegmentLayoutRef = new WeakReference<>(newSegmentLayout); newSegmentLayout.updateLayout(); diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/VotingButton.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/VotingButton.java index 2403b5a35..30fee1840 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/VotingButton.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/ui/VotingButton.java @@ -59,8 +59,7 @@ public class VotingButton { } private static boolean isButtonEnabled() { - return Settings.SB_ENABLED.get() && Settings.SB_VOTING_BUTTON.get() - && SegmentPlaybackController.videoHasSegments() + return Settings.SB_ENABLED.get() && Settings.SB_CREATE_NEW_SEGMENT.get() && !SegmentPlaybackController.isAdProgressTextVisible(); } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsHostActivity.kt b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsHostActivity.kt index 7fafd83a7..dde62492d 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsHostActivity.kt +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/SwipeControlsHostActivity.kt @@ -8,6 +8,7 @@ import android.view.MotionEvent import android.view.ViewGroup import app.revanced.extension.shared.Logger.printDebug import app.revanced.extension.shared.Logger.printException +import app.revanced.extension.youtube.patches.VersionCheckPatch import app.revanced.extension.youtube.settings.Settings import app.revanced.extension.youtube.shared.PlayerType import app.revanced.extension.youtube.swipecontrols.controller.AudioVolumeController @@ -237,6 +238,8 @@ class SwipeControlsHostActivity : Activity() { */ @Suppress("unused") @JvmStatic - fun allowSwipeChangeVideo(original: Boolean): Boolean = Settings.SWIPE_CHANGE_VIDEO.get() + fun allowSwipeChangeVideo(original: Boolean): Boolean = + // Feature can cause crashing if forced in newer targets. + !VersionCheckPatch.IS_20_22_OR_GREATER && Settings.SWIPE_CHANGE_VIDEO.get() } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/SwipeZonesController.kt b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/SwipeZonesController.kt index 2c2edb959..1a69c7aab 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/SwipeZonesController.kt +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/controller/SwipeZonesController.kt @@ -3,6 +3,7 @@ package app.revanced.extension.youtube.swipecontrols.controller import android.app.Activity import android.util.TypedValue import android.view.ViewGroup +import app.revanced.extension.shared.ResourceType import app.revanced.extension.shared.Utils import app.revanced.extension.youtube.swipecontrols.misc.Rectangle import app.revanced.extension.youtube.swipecontrols.misc.applyDimension @@ -56,7 +57,8 @@ class SwipeZonesController( /** * id for R.id.player_view */ - private val playerViewId = Utils.getResourceIdentifier(host, "player_view", "id") + private val playerViewId = Utils.getResourceIdentifier( + host, ResourceType.ID, "player_view") /** * current bounding rectangle of the player diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/views/SwipeControlsOverlayLayout.kt b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/views/SwipeControlsOverlayLayout.kt index 71226c082..2cec37b82 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/views/SwipeControlsOverlayLayout.kt +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/swipecontrols/views/SwipeControlsOverlayLayout.kt @@ -14,12 +14,13 @@ import android.util.AttributeSet import android.view.HapticFeedbackConstants import android.view.View import android.widget.RelativeLayout +import app.revanced.extension.shared.ResourceType import app.revanced.extension.shared.StringRef.str import app.revanced.extension.shared.Utils import app.revanced.extension.youtube.swipecontrols.SwipeControlsConfigurationProvider import app.revanced.extension.youtube.swipecontrols.misc.SwipeControlsOverlay -import kotlin.math.min import kotlin.math.max +import kotlin.math.min import kotlin.math.round /** @@ -53,7 +54,7 @@ class SwipeControlsOverlayLayout( // Function to retrieve drawable resources by name. private fun getDrawable(name: String): Drawable { val drawable = resources.getDrawable( - Utils.getResourceIdentifier(context, name, "drawable"), + Utils.getResourceIdentifier(context, ResourceType.DRAWABLE, name), context.theme, ) drawable.setTint(config.overlayTextColor) @@ -86,7 +87,7 @@ class SwipeControlsOverlayLayout( // Initialize horizontal progress bar. val screenWidth = resources.displayMetrics.widthPixels - val layoutWidth = (screenWidth * 4 / 5).toInt() // Cap at ~360dp. + val layoutWidth = (screenWidth * 4 / 5) // Cap at ~360dp. horizontalProgressView = HorizontalProgressView( context, config.overlayBackgroundOpacity, @@ -630,7 +631,7 @@ class VerticalProgressView( if (isMinimalStyle) { canvas.drawText(displayText, textX, textStartY, textPaint) } else { - val progressStartY = (iconEndY + padding).toFloat() + val progressStartY = (iconEndY + padding) val progressEndY = textStartY - textPaint.textSize - padding val progressHeight = progressEndY - progressStartY diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/videoplayer/VideoQualityDialogButton.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/videoplayer/VideoQualityDialogButton.java index 0c878616c..bd558c4c8 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/videoplayer/VideoQualityDialogButton.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/videoplayer/VideoQualityDialogButton.java @@ -38,6 +38,7 @@ import java.util.ArrayList; import java.util.List; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.ResourceType; import app.revanced.extension.shared.Utils; import app.revanced.extension.youtube.patches.VideoInformation; import app.revanced.extension.youtube.patches.playback.quality.RememberVideoQualityPatch; @@ -421,13 +422,13 @@ public class VideoQualityDialogButton { private static class CustomQualityAdapter extends ArrayAdapter { private static final int CUSTOM_LIST_ITEM_CHECKED_ID = Utils.getResourceIdentifier( - "revanced_custom_list_item_checked", "layout"); + ResourceType.LAYOUT, "revanced_custom_list_item_checked"); private static final int CHECK_ICON_ID = Utils.getResourceIdentifier( - "revanced_check_icon", "id"); + ResourceType.ID, "revanced_check_icon"); private static final int CHECK_ICON_PLACEHOLDER_ID = Utils.getResourceIdentifier( - "revanced_check_icon_placeholder", "id"); + ResourceType.ID, "revanced_check_icon_placeholder"); private static final int ITEM_TEXT_ID = Utils.getResourceIdentifier( - "revanced_item_text", "id"); + ResourceType.ID, "revanced_item_text"); private int selectedPosition = -1; diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f55818425..618e90c20 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,8 +1,8 @@ [versions] -revanced-patcher = "21.0.0" +revanced-patcher = "22.0.0" # Tracking https://github.com/google/smali/issues/64. #noinspection GradleDependency -smali = "3.0.5" +smali = "3.0.8" # 8.3.0 causes java verifier error: https://github.com/ReVanced/revanced-patches/issues/2818. #noinspection GradleDependency agp = "8.2.2" diff --git a/patches/api/patches.api b/patches/api/patches.api index 122bb38bc..6f1c3bdab 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -64,10 +64,6 @@ public final class app/revanced/patches/all/misc/debugging/EnableAndroidDebuggin public static final fun getEnableAndroidDebuggingPatch ()Lapp/revanced/patcher/patch/ResourcePatch; } -public final class app/revanced/patches/all/misc/directory/ChangeDataDirectoryLocationPatchKt { - public static final fun getChangeDataDirectoryLocationPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/all/misc/directory/documentsprovider/ExportInternalDataDocumentsProviderPatchKt { public static final fun getExportInternalDataDocumentsProviderPatch ()Lapp/revanced/patcher/patch/ResourcePatch; } @@ -152,10 +148,6 @@ public final class app/revanced/patches/angulus/ads/RemoveAdsPatchKt { public static final fun getAngulusPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/backdrops/misc/pro/ProUnlockPatchKt { - public static final fun getProUnlockPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/bandcamp/limitations/RemovePlayLimitsPatchKt { public static final fun getRemovePlayLimitsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -232,10 +224,6 @@ public final class app/revanced/patches/googlephotos/misc/gms/GmsCoreSupportPatc public static final fun getGmsCoreSupportPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/googlephotos/misc/preferences/RestoreHiddenBackUpWhileChargingTogglePatchKt { - public static final fun getRestoreHiddenBackUpWhileChargingTogglePatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/googlerecorder/restrictions/RemoveDeviceRestrictionsKt { public static final fun getRemoveDeviceRestrictionsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -308,14 +296,6 @@ public final class app/revanced/patches/messenger/inbox/HideInboxSubtabsPatchKt public static final fun getHideInboxSubtabsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/messenger/inputfield/DisableSwitchingEmojiToStickerPatchKt { - public static final fun getDisableSwitchingEmojiToStickerPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - -public final class app/revanced/patches/messenger/inputfield/DisableTypingIndicatorPatchKt { - public static final fun getDisableTypingIndicatorPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/messenger/layout/HideFacebookButtonPatchKt { public static final fun getHideFacebookButtonPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -328,14 +308,6 @@ public final class app/revanced/patches/messenger/misc/extension/ExtensionPatchK public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/messenger/navbar/RemoveMetaAITabPatchKt { - public static final fun getRemoveMetaAITabPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - -public final class app/revanced/patches/meta/ads/HideAdsPatchKt { - public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/mifitness/misc/locale/ForceEnglishLocalePatchKt { public static final fun getForceEnglishLocalePatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -356,10 +328,6 @@ public final class app/revanced/patches/music/interaction/permanentrepeat/Perman public static final fun getPermanentRepeatPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/music/interaction/permanentshuffle/PermanentShufflePatchKt { - public static final fun getPermanentShufflePatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/music/layout/compactheader/HideCategoryBarKt { public static final fun getHideCategoryBar ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -412,10 +380,6 @@ public final class app/revanced/patches/netguard/broadcasts/removerestriction/Re public static final fun getRemoveBroadcastsRestrictionPatch ()Lapp/revanced/patcher/patch/ResourcePatch; } -public final class app/revanced/patches/nfctoolsse/misc/pro/UnlockProPatchKt { - public static final fun getUnlockProPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/nunl/ads/HideAdsPatchKt { public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -424,10 +388,6 @@ public final class app/revanced/patches/nunl/firebase/SpoofCertificatePatchKt { public static final fun getSpoofCertificatePatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/nyx/misc/pro/UnlockProPatchKt { - public static final fun getUnlockProPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/openinghours/misc/fix/crash/FixCrashPatchKt { public static final fun getFixCrashPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -654,16 +614,11 @@ public final class app/revanced/patches/reddit/customclients/sync/syncforreddit/ public static final fun getFixVideoDownloadsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatchKt { - public static final fun getFixVideoDownloadsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/reddit/layout/disablescreenshotpopup/DisableScreenshotPopupPatchKt { public static final fun getDisableScreenshotPopupPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } public final class app/revanced/patches/reddit/layout/premiumicon/UnlockPremiumIconPatchKt { - public static final fun getUnlockPremiumIconPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getUnlockPremiumIconsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -689,26 +644,22 @@ public final class app/revanced/patches/shared/misc/extension/ExtensionHook { public final class app/revanced/patches/shared/misc/extension/SharedExtensionPatchKt { public static final fun extensionHook (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lapp/revanced/patcher/Fingerprint;)Lapp/revanced/patches/shared/misc/extension/ExtensionHook; - public static final fun extensionHook (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patches/shared/misc/extension/ExtensionHook; + public static final fun extensionHook (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function0; public static synthetic fun extensionHook$default (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lapp/revanced/patcher/Fingerprint;ILjava/lang/Object;)Lapp/revanced/patches/shared/misc/extension/ExtensionHook; - public static synthetic fun extensionHook$default (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patches/shared/misc/extension/ExtensionHook; - public static final fun sharedExtensionPatch (Ljava/lang/String;[Lapp/revanced/patches/shared/misc/extension/ExtensionHook;)Lapp/revanced/patcher/patch/BytecodePatch; - public static final fun sharedExtensionPatch ([Lapp/revanced/patches/shared/misc/extension/ExtensionHook;)Lapp/revanced/patcher/patch/BytecodePatch; + public static synthetic fun extensionHook$default (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/jvm/functions/Function0; + public static final fun sharedExtensionPatch (Ljava/lang/String;[Lkotlin/jvm/functions/Function0;)Lapp/revanced/patcher/patch/BytecodePatch; + public static final fun sharedExtensionPatch ([Lkotlin/jvm/functions/Function0;)Lapp/revanced/patcher/patch/BytecodePatch; } public final class app/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatchKt { public static final fun getVerticalScrollPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/shared/misc/gms/FingerprintsKt { - public static final field GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME Ljava/lang/String; -} - public final class app/revanced/patches/shared/misc/gms/GmsCoreSupportPatchKt { public static final fun gmsCoreSupportPatch (Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/Fingerprint;Ljava/util/Set;Lapp/revanced/patcher/Fingerprint;Lapp/revanced/patcher/patch/Patch;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/BytecodePatch; public static synthetic fun gmsCoreSupportPatch$default (Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/Fingerprint;Ljava/util/Set;Lapp/revanced/patcher/Fingerprint;Lapp/revanced/patcher/patch/Patch;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/BytecodePatch; - public static final fun gmsCoreSupportResourcePatch (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/patch/Option;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/ResourcePatch; - public static synthetic fun gmsCoreSupportResourcePatch$default (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/patch/Option;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/ResourcePatch; + public static final fun gmsCoreSupportResourcePatch (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/patch/Option;ZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/ResourcePatch; + public static synthetic fun gmsCoreSupportResourcePatch$default (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/patch/Option;ZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/ResourcePatch; } public final class app/revanced/patches/shared/misc/hex/HexPatchBuilder : java/util/Set, kotlin/jvm/internal/markers/KMappedMarker { @@ -747,23 +698,64 @@ public final class app/revanced/patches/shared/misc/hex/Replacement { } public final class app/revanced/patches/shared/misc/mapping/ResourceElement { - public final fun component1 ()Ljava/lang/String; + public fun (Lapp/revanced/patches/shared/misc/mapping/ResourceType;Ljava/lang/String;J)V + public final fun component1 ()Lapp/revanced/patches/shared/misc/mapping/ResourceType; public final fun component2 ()Ljava/lang/String; public final fun component3 ()J - public final fun copy (Ljava/lang/String;Ljava/lang/String;J)Lapp/revanced/patches/shared/misc/mapping/ResourceElement; - public static synthetic fun copy$default (Lapp/revanced/patches/shared/misc/mapping/ResourceElement;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lapp/revanced/patches/shared/misc/mapping/ResourceElement; + public final fun copy (Lapp/revanced/patches/shared/misc/mapping/ResourceType;Ljava/lang/String;J)Lapp/revanced/patches/shared/misc/mapping/ResourceElement; + public static synthetic fun copy$default (Lapp/revanced/patches/shared/misc/mapping/ResourceElement;Lapp/revanced/patches/shared/misc/mapping/ResourceType;Ljava/lang/String;JILjava/lang/Object;)Lapp/revanced/patches/shared/misc/mapping/ResourceElement; public fun equals (Ljava/lang/Object;)Z public final fun getId ()J public final fun getName ()Ljava/lang/String; - public final fun getType ()Ljava/lang/String; + public final fun getType ()Lapp/revanced/patches/shared/misc/mapping/ResourceType; public fun hashCode ()I public fun toString ()Ljava/lang/String; } public final class app/revanced/patches/shared/misc/mapping/ResourceMappingPatchKt { - public static final fun get (Ljava/util/List;Ljava/lang/String;Ljava/lang/String;)J + public static final fun getResourceElements ()Ljava/util/Collection; + public static final fun getResourceId (Lapp/revanced/patches/shared/misc/mapping/ResourceType;Ljava/lang/String;)J public static final fun getResourceMappingPatch ()Lapp/revanced/patcher/patch/ResourcePatch; - public static final fun getResourceMappings ()Ljava/util/List; + public static final fun hasResourceId (Lapp/revanced/patches/shared/misc/mapping/ResourceType;Ljava/lang/String;)Z + public static final fun resourceLiteral (Lapp/revanced/patches/shared/misc/mapping/ResourceType;Ljava/lang/String;I)Lapp/revanced/patcher/LiteralFilter; + public static synthetic fun resourceLiteral$default (Lapp/revanced/patches/shared/misc/mapping/ResourceType;Ljava/lang/String;IILjava/lang/Object;)Lapp/revanced/patcher/LiteralFilter; +} + +public final class app/revanced/patches/shared/misc/mapping/ResourceType : java/lang/Enum { + public static final field ANIM Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field ANIMATOR Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field ARRAY Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field ATTR Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field BOOL Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field COLOR Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field Companion Lapp/revanced/patches/shared/misc/mapping/ResourceType$Companion; + public static final field DIMEN Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field DRAWABLE Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field FONT Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field FRACTION Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field ID Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field INTEGER Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field INTERPOLATOR Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field LAYOUT Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field MENU Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field MIPMAP Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field NAVIGATION Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field PLURALS Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field RAW Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field STRING Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field STYLE Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field STYLEABLE Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field TRANSITION Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field VALUES Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static final field XML Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public final fun getValue ()Ljava/lang/String; + public static fun valueOf (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/mapping/ResourceType; + public static fun values ()[Lapp/revanced/patches/shared/misc/mapping/ResourceType; +} + +public final class app/revanced/patches/shared/misc/mapping/ResourceType$Companion { + public final fun fromValue (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/mapping/ResourceType; } public final class app/revanced/patches/shared/misc/pairip/license/DisableLicenseCheckPatchKt { @@ -773,7 +765,6 @@ public final class app/revanced/patches/shared/misc/pairip/license/DisableLicens public final class app/revanced/patches/shared/misc/settings/SettingsPatchKt { public static final fun overrideThemeColors (Ljava/lang/String;Ljava/lang/String;)V public static final fun settingsPatch (Ljava/util/List;Ljava/util/Set;)Lapp/revanced/patcher/patch/ResourcePatch; - public static final fun settingsPatch (Lkotlin/Pair;Ljava/util/Set;)Lapp/revanced/patcher/patch/ResourcePatch; public static synthetic fun settingsPatch$default (Ljava/util/List;Ljava/util/Set;ILjava/lang/Object;)Lapp/revanced/patcher/patch/ResourcePatch; } @@ -866,8 +857,8 @@ public final class app/revanced/patches/shared/misc/settings/preference/ListPref public fun ()V public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/util/resource/ArrayResource;Lapp/revanced/util/resource/ArrayResource;)V public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/util/resource/ArrayResource;Lapp/revanced/util/resource/ArrayResource;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;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 (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun getEntries ()Lapp/revanced/util/resource/ArrayResource; public final fun getEntriesKey ()Ljava/lang/String; public final fun getEntryValues ()Lapp/revanced/util/resource/ArrayResource; @@ -979,14 +970,6 @@ public final class app/revanced/patches/spotify/layout/theme/CustomThemePatchKt public static final fun getCustomThemePatch ()Lapp/revanced/patcher/patch/ResourcePatch; } -public final class app/revanced/patches/spotify/lite/ondemand/OnDemandPatchKt { - public static final fun getOnDemandPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - -public final class app/revanced/patches/spotify/misc/UnlockPremiumPatchKt { - public static final fun getUnlockPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/spotify/misc/extension/ExtensionPatchKt { public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -995,14 +978,6 @@ public final class app/revanced/patches/spotify/misc/fix/SpoofClientPatchKt { public static final fun getSpoofClientPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/spotify/misc/fix/SpoofPackageInfoPatchKt { - public static final fun getSpoofPackageInfoPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - -public final class app/revanced/patches/spotify/misc/fix/SpoofSignaturePatchKt { - public static final fun getSpoofSignaturePatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/spotify/misc/fix/login/FixFacebookLoginPatchKt { public static final fun getFixFacebookLoginPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1019,10 +994,6 @@ public final class app/revanced/patches/spotify/misc/widgets/FixThirdPartyLaunch public static final fun getFixThirdPartyLaunchersWidgets ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/spotify/navbar/PremiumNavbarTabPatchKt { - public static final fun getPremiumNavbarTabPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/stocard/layout/HideOffersTabPatchKt { public static final fun getHideOffersTabPatch ()Lapp/revanced/patcher/patch/ResourcePatch; } @@ -1239,10 +1210,6 @@ public final class app/revanced/patches/twitter/misc/links/SanitizeSharingLinksP public static final fun getSanitizeSharingLinksPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/vsco/misc/pro/UnlockProPatchKt { - public static final fun getUnlockProPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/warnwetter/misc/firebasegetcert/FirebaseGetCertPatchKt { public static final fun getFirebaseGetCertPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1251,10 +1218,6 @@ public final class app/revanced/patches/warnwetter/misc/promocode/PromoCodeUnloc public static final fun getPromoCodeUnlockPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/windyapp/misc/unlockpro/UnlockProPatchKt { - public static final fun getUnlockProPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/youtube/ad/general/HideAdsPatchKt { public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1276,7 +1239,6 @@ public final class app/revanced/patches/youtube/interaction/dialog/RemoveViewerD } public final class app/revanced/patches/youtube/interaction/doubletap/DisableChapterSkipDoubleTapPatchKt { - public static final fun getDisableChapterSkipDoubleTapPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getDisableDoubleTapActionsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1353,15 +1315,7 @@ public final class app/revanced/patches/youtube/layout/hide/fullscreenambientmod } public final class app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatchKt { - public static final fun getAlbumCardId ()J - public static final fun getBarContainerHeightId ()J - public static final fun getCrowdfundingBoxId ()J - public static final fun getExpandButtonDownId ()J - public static final fun getFabButtonId ()J - public static final fun getFilterBarHeightId ()J public static final fun getHideLayoutComponentsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; - public static final fun getRelatedChipCloudMarginId ()J - public static final fun getYouTubeLogo ()J } public final class app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatchKt { @@ -1380,10 +1334,6 @@ public final class app/revanced/patches/youtube/layout/hide/rollingnumber/Disabl public static final fun getDisableRollingNumberAnimationPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatchKt { - public static final fun getHideSeekbarPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatchKt { public static final fun getHideShortsComponentsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1392,10 +1342,6 @@ public final class app/revanced/patches/youtube/layout/hide/signintotvpopup/Disa public static final fun getDisableSignInToTvPopupPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatchKt { - public static final fun getDisableSuggestedVideoEndScreenPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/youtube/layout/hide/time/HideTimestampPatchKt { public static final fun getHideTimestampPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1408,14 +1354,6 @@ public final class app/revanced/patches/youtube/layout/panels/popup/PlayerPopupP public static final fun getPlayerPopupPanelsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatchKt { - public static final fun getPlayerControlsBackgroundPatch ()Lapp/revanced/patcher/patch/ResourcePatch; -} - -public final class app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenKt { - public static final fun getOpenVideosFullscreen ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenPatchKt { public static final fun getOpenVideosFullscreenPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1470,10 +1408,6 @@ public final class app/revanced/patches/youtube/layout/startupshortsreset/Disabl public static final fun getDisableResumingShortsOnStartupPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatchKt { - public static final fun getEnableTabletLayoutPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/youtube/layout/theme/LithoColorHookPatchKt { public static final fun getLithoColorHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getLithoColorOverrideHook ()Lkotlin/jvm/functions/Function2; @@ -1519,14 +1453,6 @@ public final class app/revanced/patches/youtube/misc/extension/SharedExtensionPa public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatchKt { - public static final fun getSpoofVideoStreamsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - -public final class app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatchKt { - public static final fun getUserAgentClientSpoofPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/youtube/misc/fix/playbackspeed/FIxPlaybackSpeedWhilePlayingPatchKt { public static final fun getFixPlaybackSpeedWhilePlayingPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1574,7 +1500,6 @@ public final class app/revanced/patches/youtube/misc/playercontrols/PlayerContro public final class app/revanced/patches/youtube/misc/playercontrols/PlayerControlsPatchKt { public static final fun getAddBottomControl ()Lkotlin/jvm/functions/Function1; public static final fun getPlayerControlsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; - public static final fun getPlayerControlsResourcePatch ()Lapp/revanced/patcher/patch/ResourcePatch; public static final fun initializeBottomControl (Ljava/lang/String;)V public static final fun injectVisibilityCheckCall (Ljava/lang/String;)V } @@ -1585,9 +1510,6 @@ public final class app/revanced/patches/youtube/misc/playertype/PlayerTypeHookPa public final class app/revanced/patches/youtube/misc/playservice/VersionCheckPatchKt { public static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch; - public static final fun is_19_03_or_greater ()Z - public static final fun is_19_04_or_greater ()Z - public static final fun is_19_16_or_greater ()Z public static final fun is_19_17_or_greater ()Z public static final fun is_19_18_or_greater ()Z public static final fun is_19_23_or_greater ()Z @@ -1612,6 +1534,15 @@ public final class app/revanced/patches/youtube/misc/playservice/VersionCheckPat public static final fun is_20_10_or_greater ()Z public static final fun is_20_14_or_greater ()Z public static final fun is_20_15_or_greater ()Z + public static final fun is_20_19_or_greater ()Z + public static final fun is_20_20_or_greater ()Z + public static final fun is_20_21_or_greater ()Z + public static final fun is_20_22_or_greater ()Z + public static final fun is_20_26_or_greater ()Z + public static final fun is_20_28_or_greater ()Z + public static final fun is_20_30_or_greater ()Z + public static final fun is_20_31_or_greater ()Z + public static final fun is_20_34_or_greater ()Z } public final class app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatchKt { @@ -1654,10 +1585,6 @@ public final class app/revanced/patches/youtube/misc/spoof/UserAgentClientSpoofP public static final fun getUserAgentClientSpoofPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/youtube/misc/zoomhaptics/ZoomHapticsPatchKt { - public static final fun getZoomHapticsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/youtube/video/audio/ForceOriginalAudioPatchKt { public static final fun getForceOriginalAudioPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -1722,14 +1649,6 @@ public final class app/revanced/patches/youtube/video/videoid/VideoIdPatchKt { public static final fun hookVideoId (Ljava/lang/String;)V } -public final class app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatchKt { - public static final fun getRestoreOldVideoQualityMenuPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - -public final class app/revanced/patches/yuka/misc/unlockpremium/UnlockPremiumPatchKt { - public static final fun getUnlockPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/util/BytecodeUtilsKt { public static final fun addInstructionsAtControlFlowLabel (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V public static final fun addInstructionsAtControlFlowLabel (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;[Lapp/revanced/patcher/util/smali/ExternalLabel;)V @@ -1779,6 +1698,7 @@ public final class app/revanced/util/BytecodeUtilsKt { public static final fun indexOfFirstResourceIdOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I public static final fun injectHideViewCall (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;IILjava/lang/String;Ljava/lang/String;)V public static final fun literal (Lapp/revanced/patcher/FingerprintBuilder;Lkotlin/jvm/functions/Function0;)V + public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;)V public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;B)V public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;C)V public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;D)V @@ -1786,9 +1706,9 @@ public final class app/revanced/util/BytecodeUtilsKt { public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)V public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;J)V public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/String;)V + public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/Void;)V public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;S)V public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Z)V - public static synthetic fun returnEarly$default (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ZILjava/lang/Object;)V public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;B)V public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;C)V public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;D)V @@ -1796,6 +1716,7 @@ public final class app/revanced/util/BytecodeUtilsKt { public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)V public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;J)V public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/String;)V + public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/Void;)V public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;S)V public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Z)V public static final fun transformMethods (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;)V diff --git a/patches/build.gradle.kts b/patches/build.gradle.kts index 6153055b9..a34a628fc 100644 --- a/patches/build.gradle.kts +++ b/patches/build.gradle.kts @@ -12,6 +12,12 @@ patches { } } +repositories { + mavenLocal() + gradlePluginPortal() + google() +} + dependencies { // Required due to smali, or build fails. Can be removed once smali is bumped. implementation(libs.guava) diff --git a/patches/src/main/kotlin/app/revanced/patches/all/misc/directory/ChangeDataDirectoryLocationPatch.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/directory/ChangeDataDirectoryLocationPatch.kt deleted file mode 100644 index 8046c11fc..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/all/misc/directory/ChangeDataDirectoryLocationPatch.kt +++ /dev/null @@ -1,19 +0,0 @@ -package app.revanced.patches.all.misc.directory - -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.all.misc.directory.documentsprovider.exportInternalDataDocumentsProviderPatch - -@Suppress("unused") -@Deprecated( - "Superseded by internalDataDocumentsProviderPatch", - ReplaceWith("internalDataDocumentsProviderPatch"), -) -val changeDataDirectoryLocationPatch = bytecodePatch( - // name = "Change data directory location", - description = "Changes the data directory in the application from " + - "the app internal storage directory to /sdcard/android/data accessible by root-less devices." + - "Using this patch can cause unexpected issues with some apps.", - use = false, -) { - dependsOn(exportInternalDataDocumentsProviderPatch) -} diff --git a/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/TransformInstructionsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/TransformInstructionsPatch.kt index 6564f4f26..8e694f103 100644 --- a/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/TransformInstructionsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/TransformInstructionsPatch.kt @@ -36,7 +36,7 @@ fun transformInstructionsPatch( } }.forEach { (classDef, methods) -> // And finally transform the methods... - val mutableClass = proxy(classDef).mutableClass + val mutableClass = mutableClassBy(classDef) methods.map(mutableClass::findMutableMethodOf).forEach methods@{ mutableMethod -> val patchIndices = findPatchIndices(mutableClass, mutableMethod)?.toCollection(ArrayDeque()) diff --git a/patches/src/main/kotlin/app/revanced/patches/amazon/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/amazon/Fingerprints.kt index 1339149f4..35d31a5f9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/amazon/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/amazon/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.amazon import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val deepLinkingFingerprint = fingerprint { +internal val deepLinkingFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE) returns("Z") parameters("L") diff --git a/patches/src/main/kotlin/app/revanced/patches/angulus/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/angulus/ads/Fingerprints.kt index 3196adb7e..12ded4c06 100644 --- a/patches/src/main/kotlin/app/revanced/patches/angulus/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/angulus/ads/Fingerprints.kt @@ -11,7 +11,7 @@ import com.android.tools.smali.dexlib2.AccessFlags // This fingerprint targets a method that returns the daily measurement count. // This method is used to determine if the user has reached the daily limit of measurements. -internal val getDailyMeasurementCountFingerprint = fingerprint { +internal val getDailyMeasurementCountFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE) returns("I") strings("dailyMeasurementCount") diff --git a/patches/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/Fingerprints.kt deleted file mode 100644 index f8b146622..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/Fingerprints.kt +++ /dev/null @@ -1,19 +0,0 @@ -package app.revanced.patches.backdrops.misc.pro - -import app.revanced.patcher.fingerprint -import com.android.tools.smali.dexlib2.Opcode - -@Deprecated("Fingerprint no longer resolves and will soon be deleted.") -internal val proUnlockFingerprint = fingerprint { - opcodes( - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - ) - custom { method, _ -> - method.name == "lambda\$existPurchase\$0" && - method.definingClass == "Lcom/backdrops/wallpapers/data/local/DatabaseHandlerIAB;" - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/ProUnlockPatch.kt b/patches/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/ProUnlockPatch.kt deleted file mode 100644 index 0516e1eb7..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/ProUnlockPatch.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.backdrops.misc.pro - -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.patch.bytecodePatch -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction - -@Suppress("unused") -@Deprecated("This patch no longer works and will soon be deleted.") -val proUnlockPatch = bytecodePatch{ - compatibleWith("com.backdrops.wallpapers") - - execute { - val registerIndex = proUnlockFingerprint.patternMatch!!.endIndex - 1 - - proUnlockFingerprint.method.apply { - val register = getInstruction(registerIndex).registerA - addInstruction( - proUnlockFingerprint.patternMatch!!.endIndex, - "const/4 v$register, 0x1", - ) - } - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/bandcamp/limitations/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/bandcamp/limitations/Fingerprints.kt index 15d306bc9..c9eccaea6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/bandcamp/limitations/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/bandcamp/limitations/Fingerprints.kt @@ -2,6 +2,6 @@ package app.revanced.patches.bandcamp.limitations import app.revanced.patcher.fingerprint -internal val handlePlaybackLimitsFingerprint = fingerprint { +internal val handlePlaybackLimitsFingerprint by fingerprint { strings("track_id", "play_count") } diff --git a/patches/src/main/kotlin/app/revanced/patches/cieid/restrictions/root/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/cieid/restrictions/root/Fingerprints.kt index 387b0a0be..6f9c9c2c6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/cieid/restrictions/root/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/cieid/restrictions/root/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.cieid.restrictions.root import app.revanced.patcher.fingerprint -internal val checkRootFingerprint = fingerprint { +internal val checkRootFingerprint by fingerprint { custom { method, _ -> method.name == "onResume" && method.definingClass == "Lit/ipzs/cieid/BaseActivity;" } diff --git a/patches/src/main/kotlin/app/revanced/patches/cricbuzz/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/cricbuzz/ads/Fingerprints.kt index 9dd6844fd..4a4868099 100644 --- a/patches/src/main/kotlin/app/revanced/patches/cricbuzz/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/cricbuzz/ads/Fingerprints.kt @@ -3,12 +3,12 @@ package app.revanced.patches.cricbuzz.ads import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode -internal val userStateSwitchFingerprint = fingerprint { +internal val userStateSwitchFingerprint by fingerprint { opcodes(Opcode.SPARSE_SWITCH) strings("key.user.state", "NA") } -internal val cb11ConstructorFingerprint = fingerprint { +internal val cb11ConstructorFingerprint by fingerprint { parameters( "Ljava/lang/String;", "Ljava/lang/String;", @@ -26,7 +26,7 @@ internal val cb11ConstructorFingerprint = fingerprint { } } -internal val getBottomBarFingerprint = fingerprint { +internal val getBottomBarFingerprint by fingerprint { custom { method, classDef -> method.name == "getBottomBar" && classDef.endsWith("HomeMenu;") } diff --git a/patches/src/main/kotlin/app/revanced/patches/crunchyroll/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/crunchyroll/ads/Fingerprints.kt index 0266e0344..6184f77a2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/crunchyroll/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/crunchyroll/ads/Fingerprints.kt @@ -2,6 +2,6 @@ package app.revanced.patches.crunchyroll.ads import app.revanced.patcher.fingerprint -internal val videoUrlReadyToStringFingerprint = fingerprint { +internal val videoUrlReadyToStringFingerprint by fingerprint { strings("VideoUrlReady(url=", ", enableAds=") } diff --git a/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/DisableAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/DisableAdsPatch.kt index af93ceb16..f33cb2d10 100644 --- a/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/DisableAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/DisableAdsPatch.kt @@ -19,16 +19,16 @@ val disableAdsPatch = bytecodePatch( // SharedPreferences has a debug boolean value with key "disable_ads", which maps to "DebugCategory.DISABLE_ADS". // // MonetizationDebugSettings seems to be the most general setting to work fine. - initializeMonetizationDebugSettingsFingerprint - .match(monetizationDebugSettingsToStringFingerprint.classDef) - .method.apply { - val insertIndex = initializeMonetizationDebugSettingsFingerprint.patternMatch!!.startIndex - val register = getInstruction(insertIndex).registerA + initializeMonetizationDebugSettingsFingerprint.match( + monetizationDebugSettingsToStringFingerprint.classDef + ).method.apply { + val insertIndex = initializeMonetizationDebugSettingsFingerprint.instructionMatches.first().index + val register = getInstruction(insertIndex).registerA - addInstructions( - insertIndex, - "const/4 v$register, 0x1", - ) - } + addInstructions( + insertIndex, + "const/4 v$register, 0x1", + ) + } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/Fingerprints.kt index 8ec0068da..b7152154c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/duolingo/ad/Fingerprints.kt @@ -4,14 +4,14 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val initializeMonetizationDebugSettingsFingerprint = fingerprint { +internal val initializeMonetizationDebugSettingsFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) returns("V") // Parameters have not been reliable for fingerprinting between versions. opcodes(Opcode.IPUT_BOOLEAN) } -internal val monetizationDebugSettingsToStringFingerprint = fingerprint { +internal val monetizationDebugSettingsToStringFingerprint by fingerprint { strings("MonetizationDebugSettings(") // Partial string match. custom { method, _ -> method.name == "toString" } -} \ No newline at end of file +} diff --git a/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt b/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt index 833f9dd7d..715bb80de 100644 --- a/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt @@ -14,7 +14,7 @@ val enableDebugMenuPatch = bytecodePatch( execute { initializeBuildConfigProviderFingerprint.method.apply { - val insertIndex = initializeBuildConfigProviderFingerprint.patternMatch!!.startIndex + val insertIndex = initializeBuildConfigProviderFingerprint.instructionMatches.first().index val register = getInstruction(insertIndex).registerA addInstructions( diff --git a/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/Fingerprints.kt index 543e40b43..b1ec38294 100644 --- a/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/duolingo/debug/Fingerprints.kt @@ -11,9 +11,8 @@ import com.android.tools.smali.dexlib2.Opcode * - `isDebug`: compares "release" with "debug" <-- we want to force this to `true` */ -internal val initializeBuildConfigProviderFingerprint = fingerprint { +internal val initializeBuildConfigProviderFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") opcodes(Opcode.IPUT_BOOLEAN) strings("debug", "release", "china") } diff --git a/patches/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/Fingerprints.kt index e84a448ba..396f44ff0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val baseModelMapperFingerprint = fingerprint { +internal val baseModelMapperFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Lcom/facebook/graphql/modelutil/BaseModelWithTree;") parameters("Ljava/lang/Class", "I", "I") @@ -17,7 +17,7 @@ internal val baseModelMapperFingerprint = fingerprint { ) } -internal val getSponsoredDataModelTemplateFingerprint = fingerprint { +internal val getSponsoredDataModelTemplateFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters() @@ -33,7 +33,7 @@ internal val getSponsoredDataModelTemplateFingerprint = fingerprint { } } -internal val getStoryVisibilityFingerprint = fingerprint { +internal val getStoryVisibilityFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Ljava/lang/String;") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatch.kt b/patches/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatch.kt index 49d54c2b3..abb222296 100644 --- a/patches/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatch.kt @@ -67,7 +67,7 @@ val hideSponsoredStoriesPatch = bytecodePatch( // Check if the parameter type is GraphQLStory and if sponsoredDataModelGetter returns a non-null value. // If so, hide the story by setting the visibility to StoryVisibility.GONE. getStoryVisibilityFingerprint.method.addInstructionsWithLabels( - getStoryVisibilityFingerprint.patternMatch!!.startIndex, + getStoryVisibilityFingerprint.instructionMatches.first().index, """ instance-of v0, p0, $graphQlStoryClassDescriptor if-eqz v0, :resume_normal diff --git a/patches/src/main/kotlin/app/revanced/patches/facebook/ads/story/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/facebook/ads/story/Fingerprints.kt index 293d7ee82..0a93699f0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/facebook/ads/story/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/facebook/ads/story/Fingerprints.kt @@ -3,11 +3,11 @@ package app.revanced.patches.facebook.ads.story import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue -internal val adsInsertionFingerprint = fieldFingerprint( +internal val adsInsertionFingerprint by fieldFingerprint( fieldValue = "AdBucketDataSourceUtil\$attemptAdsInsertion\$1", ) -internal val fetchMoreAdsFingerprint = fieldFingerprint( +internal val fetchMoreAdsFingerprint by fieldFingerprint( fieldValue = "AdBucketDataSourceUtil\$attemptFetchMoreAds\$1", ) diff --git a/patches/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/Fingerprints.kt index 4c8ee1c54..2347d1143 100644 --- a/patches/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/Fingerprints.kt @@ -5,7 +5,7 @@ import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint // Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.AttestationHelper#isBootStateOk (3.0.1) -internal val bootStateFingerprint = fingerprint { +internal val bootStateFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("Z") opcodes( @@ -30,7 +30,7 @@ internal val bootStateFingerprint = fingerprint { } // Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.AttestationHelper#createKey (3.0.1) -internal val createKeyFingerprint = fingerprint { +internal val createKeyFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("Z") strings("attestation", "SHA-256", "random", "EC", "AndroidKeyStore") diff --git a/patches/src/main/kotlin/app/revanced/patches/finanzonline/detection/root/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/finanzonline/detection/root/Fingerprints.kt index fec7f1249..7460461e4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/finanzonline/detection/root/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/finanzonline/detection/root/Fingerprints.kt @@ -5,7 +5,7 @@ import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint // Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.RootDetection#isRooted (3.0.1) -internal val rootDetectionFingerprint = fingerprint { +internal val rootDetectionFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("L") parameters("L") diff --git a/patches/src/main/kotlin/app/revanced/patches/googlenews/customtabs/EnableCustomTabsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/googlenews/customtabs/EnableCustomTabsPatch.kt index ee7997a54..6057630e6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/googlenews/customtabs/EnableCustomTabsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/googlenews/customtabs/EnableCustomTabsPatch.kt @@ -14,7 +14,7 @@ val enableCustomTabsPatch = bytecodePatch( execute { launchCustomTabFingerprint.method.apply { - val checkIndex = launchCustomTabFingerprint.patternMatch!!.endIndex + 1 + val checkIndex = launchCustomTabFingerprint.instructionMatches.last().index + 1 val register = getInstruction(checkIndex).registerA replaceInstruction(checkIndex, "const/4 v$register, 0x1") diff --git a/patches/src/main/kotlin/app/revanced/patches/googlenews/customtabs/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/googlenews/customtabs/Fingerprints.kt index 8880c010e..387d1cbf6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/googlenews/customtabs/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/googlenews/customtabs/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val launchCustomTabFingerprint = fingerprint { +internal val launchCustomTabFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) opcodes( Opcode.IPUT_OBJECT, diff --git a/patches/src/main/kotlin/app/revanced/patches/googlenews/misc/gms/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/googlenews/misc/gms/Fingerprints.kt index 6ddeb3e07..e23ac4bc4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/googlenews/misc/gms/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/googlenews/misc/gms/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.googlenews.misc.gms import app.revanced.patcher.fingerprint -internal val magazinesActivityOnCreateFingerprint = fingerprint { +internal val magazinesActivityOnCreateFingerprint by fingerprint { custom { methodDef, classDef -> methodDef.name == "onCreate" && classDef.endsWith("/StartActivity;") } diff --git a/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/backup/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/backup/Fingerprints.kt index 71dda1f3a..0c82cfe15 100644 --- a/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/backup/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/backup/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.googlephotos.misc.backup import app.revanced.patcher.fingerprint -internal val isDCIMFolderBackupControlDisabled = fingerprint { +internal val isDCIMFolderBackupControlDisabled by fingerprint { returns("Z") strings("/dcim", "/mars_files/") } diff --git a/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/features/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/features/Fingerprints.kt index 95f2a3dba..bd63a4a40 100644 --- a/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/features/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/features/Fingerprints.kt @@ -2,6 +2,6 @@ package app.revanced.patches.googlephotos.misc.features import app.revanced.patcher.fingerprint -internal val initializeFeaturesEnumFingerprint = fingerprint { +internal val initializeFeaturesEnumFingerprint by fingerprint { strings("com.google.android.apps.photos.NEXUS_PRELOAD") } diff --git a/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/gms/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/gms/Fingerprints.kt index f47c1a3d9..cbd720730 100644 --- a/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/gms/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/gms/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.googlephotos.misc.gms import app.revanced.patcher.fingerprint -internal val homeActivityOnCreateFingerprint = fingerprint { +internal val homeActivityOnCreateFingerprint by fingerprint { custom { methodDef, classDef -> methodDef.name == "onCreate" && classDef.endsWith("/HomeActivity;") } diff --git a/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/preferences/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/preferences/Fingerprints.kt deleted file mode 100644 index 54c20a7f8..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/preferences/Fingerprints.kt +++ /dev/null @@ -1,8 +0,0 @@ -package app.revanced.patches.googlephotos.misc.preferences - -import app.revanced.patcher.fingerprint - -internal val backupPreferencesFingerprint = fingerprint { - returns("Lcom/google/android/apps/photos/backup/data/BackupPreferences;") - strings("backup_prefs_had_backup_only_when_charging_enabled") -} diff --git a/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/preferences/RestoreHiddenBackUpWhileChargingTogglePatch.kt b/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/preferences/RestoreHiddenBackUpWhileChargingTogglePatch.kt deleted file mode 100644 index ea65658bd..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/googlephotos/misc/preferences/RestoreHiddenBackUpWhileChargingTogglePatch.kt +++ /dev/null @@ -1,30 +0,0 @@ -package app.revanced.patches.googlephotos.misc.preferences - -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.util.indexOfFirstInstructionOrThrow -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction - -@Deprecated("This patch no longer works and this code will soon be deleted") -@Suppress("unused") -val restoreHiddenBackUpWhileChargingTogglePatch = bytecodePatch( - description = "Restores a hidden toggle to only run backups when the device is charging." -) { - compatibleWith("com.google.android.apps.photos"("7.11.0.705590205")) - - execute { - // Patches 'backup_prefs_had_backup_only_when_charging_enabled' to always be true. - backupPreferencesFingerprint.let { - it.method.apply { - val index = indexOfFirstInstructionOrThrow( - it.stringMatches!!.first().index, - Opcode.MOVE_RESULT - ) - val register = getInstruction(index).registerA - addInstruction(index + 1, "const/4 v$register, 0x1") - } - } - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/googlerecorder/restrictions/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/googlerecorder/restrictions/Fingerprints.kt index 62e1e5f16..431ea6c26 100644 --- a/patches/src/main/kotlin/app/revanced/patches/googlerecorder/restrictions/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/googlerecorder/restrictions/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.googlerecorder.restrictions import app.revanced.patcher.fingerprint -internal val onApplicationCreateFingerprint = fingerprint { +internal val onApplicationCreateFingerprint by fingerprint { strings("com.google.android.feature.PIXEL_2017_EXPERIENCE") custom { method, classDef -> if (method.name != "onCreate") return@custom false diff --git a/patches/src/main/kotlin/app/revanced/patches/googlerecorder/restrictions/RemoveDeviceRestrictions.kt b/patches/src/main/kotlin/app/revanced/patches/googlerecorder/restrictions/RemoveDeviceRestrictions.kt index bd6921bfb..6aec4c600 100644 --- a/patches/src/main/kotlin/app/revanced/patches/googlerecorder/restrictions/RemoveDeviceRestrictions.kt +++ b/patches/src/main/kotlin/app/revanced/patches/googlerecorder/restrictions/RemoveDeviceRestrictions.kt @@ -14,7 +14,7 @@ val removeDeviceRestrictionsPatch = bytecodePatch( compatibleWith("com.google.android.apps.recorder") execute { - val featureStringIndex = onApplicationCreateFingerprint.stringMatches!!.first().index + val featureStringIndex = onApplicationCreateFingerprint.stringMatches.first().index onApplicationCreateFingerprint.method.apply { // Remove check for device restrictions. diff --git a/patches/src/main/kotlin/app/revanced/patches/hexeditor/ad/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/hexeditor/ad/Fingerprints.kt index 2fa2c5b85..bed5ce630 100644 --- a/patches/src/main/kotlin/app/revanced/patches/hexeditor/ad/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/hexeditor/ad/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.hexeditor.ad import app.revanced.patcher.fingerprint -internal val primaryAdsFingerprint = fingerprint { +internal val primaryAdsFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("PreferencesHelper;") && method.name == "isAdsDisabled" } diff --git a/patches/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/Fingerprints.kt index 84db55457..fe15366f4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.iconpackstudio.misc.pro import app.revanced.patcher.fingerprint -internal val checkProFingerprint = fingerprint { +internal val checkProFingerprint by fingerprint { returns("Z") custom { _, classDef -> classDef.endsWith("IPSPurchaseRepository;") } } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/idaustria/detection/root/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/idaustria/detection/root/Fingerprints.kt index 38f814f6d..48c0f31ff 100644 --- a/patches/src/main/kotlin/app/revanced/patches/idaustria/detection/root/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/idaustria/detection/root/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.idaustria.detection.root import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val attestationSupportedCheckFingerprint = fingerprint { +internal val attestationSupportedCheckFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("V") custom { method, classDef -> @@ -12,7 +12,7 @@ internal val attestationSupportedCheckFingerprint = fingerprint { } } -internal val bootloaderCheckFingerprint = fingerprint { +internal val bootloaderCheckFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("Z") custom { method, classDef -> @@ -21,7 +21,7 @@ internal val bootloaderCheckFingerprint = fingerprint { } } -internal val rootCheckFingerprint = fingerprint { +internal val rootCheckFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("V") custom { method, classDef -> diff --git a/patches/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/Fingerprints.kt index 61cd9605f..23e2a12ed 100644 --- a/patches/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.idaustria.detection.signature import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val spoofSignatureFingerprint = fingerprint { +internal val spoofSignatureFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE) returns("L") parameters("L") diff --git a/patches/src/main/kotlin/app/revanced/patches/inshorts/ad/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/inshorts/ad/Fingerprints.kt index 573bd72e3..151718de5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/inshorts/ad/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/inshorts/ad/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.inshorts.ad import app.revanced.patcher.fingerprint -internal val inshortsAdsFingerprint = fingerprint { +internal val inshortsAdsFingerprint by fingerprint { returns("V") strings("GoogleAdLoader", "exception in requestAd") } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/Fingerprints.kt index 3b401a842..519833d62 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/navigation/Fingerprints.kt @@ -4,7 +4,7 @@ package app.revanced.patches.instagram.hide.navigation import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode -internal val tabCreateButtonsLoopStartFingerprint = fingerprint { +internal val tabCreateButtonsLoopStartFingerprint by fingerprint { returns("V") strings("InstagramMainActivity.createTabButtons") opcodes( @@ -16,7 +16,7 @@ internal val tabCreateButtonsLoopStartFingerprint = fingerprint { ) } -internal val tabCreateButtonsLoopEndFingerprint = fingerprint { +internal val tabCreateButtonsLoopEndFingerprint by fingerprint { returns("V") strings("InstagramMainActivity.createTabButtons") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/stories/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/stories/Fingerprints.kt index 3b58aa8c2..40f6ef507 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/hide/stories/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/hide/stories/Fingerprints.kt @@ -2,8 +2,7 @@ package app.revanced.patches.instagram.hide.stories import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode - -internal val getOrCreateAvatarViewFingerprint = fingerprint { +internal val getOrCreateAvatarViewFingerprint by fingerprint { parameters() returns("L") custom { method, classDef -> diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/misc/signature/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/misc/signature/Fingerprints.kt index 47ebe189b..1890ba252 100644 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/misc/signature/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/instagram/misc/signature/Fingerprints.kt @@ -5,11 +5,11 @@ import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal val isValidSignatureClassFingerprint = fingerprint { +internal val isValidSignatureClassFingerprint by fingerprint { strings("The provider for uri '", "' is not trusted: ") } -internal val isValidSignatureMethodFingerprint = fingerprint { +internal val isValidSignatureMethodFingerprint by fingerprint { parameters("L", "Z") returns("Z") custom { method, _ -> diff --git a/patches/src/main/kotlin/app/revanced/patches/irplus/ad/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/irplus/ad/Fingerprints.kt index 30242b8d9..431bbd99a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/irplus/ad/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/irplus/ad/Fingerprints.kt @@ -3,9 +3,8 @@ package app.revanced.patches.irplus.ad import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val irplusAdsFingerprint = fingerprint { +internal val irplusAdsFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") parameters("L", "Z") strings("TAGGED") } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/lightroom/misc/login/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/lightroom/misc/login/Fingerprints.kt index 6345541e1..aefb36de6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/lightroom/misc/login/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/lightroom/misc/login/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val isLoggedInFingerprint = fingerprint { +internal val isLoggedInFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC, AccessFlags.FINAL) returns("Z") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/lightroom/misc/premium/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/lightroom/misc/premium/Fingerprints.kt index 5a00dc68c..3d001bb99 100644 --- a/patches/src/main/kotlin/app/revanced/patches/lightroom/misc/premium/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/lightroom/misc/premium/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val hasPurchasedFingerprint = fingerprint { +internal val hasPurchasedFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returns("Z") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/Fingerprints.kt index 0dfbf5cda..3914e00b1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val licenseValidationFingerprint = fingerprint { +internal val licenseValidationFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Z") parameters("Landroid/content/Context;") diff --git a/patches/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/Fingerprints.kt index 75912318b..396e7267d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val verifySignatureFingerprint = fingerprint(fuzzyPatternScanThreshold = 2) { +internal val verifySignatureFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Z") parameters("Landroid/app/Activity;") diff --git a/patches/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/Fingerprints.kt index 1f16bb10e..f6faf995a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val isFreeVersionFingerprint = fingerprint { +internal val isFreeVersionFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Ljava/lang/Boolean;") parameters("Landroid/content/Context;") diff --git a/patches/src/main/kotlin/app/revanced/patches/messenger/inbox/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/messenger/inbox/Fingerprints.kt index 185c88f94..fb5961db2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/messenger/inbox/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/messenger/inbox/Fingerprints.kt @@ -5,7 +5,7 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue -internal val createInboxSubTabsFingerprint = fingerprint { +internal val createInboxSubTabsFingerprint by fingerprint { returns("V") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) opcodes( @@ -22,7 +22,7 @@ internal val createInboxSubTabsFingerprint = fingerprint { } } -internal val loadInboxAdsFingerprint = fingerprint { +internal val loadInboxAdsFingerprint by fingerprint { returns("V") strings( "ads_load_begin", diff --git a/patches/src/main/kotlin/app/revanced/patches/messenger/inputfield/DisableSwitchingEmojiToStickerPatch.kt b/patches/src/main/kotlin/app/revanced/patches/messenger/inputfield/DisableSwitchingEmojiToStickerPatch.kt deleted file mode 100644 index b9e301725..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/messenger/inputfield/DisableSwitchingEmojiToStickerPatch.kt +++ /dev/null @@ -1,28 +0,0 @@ -package app.revanced.patches.messenger.inputfield - -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction -import app.revanced.patcher.patch.bytecodePatch -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction - -/** - * This patch will be deleted soon. - * - * Pull requests to update this patch to the latest app target are invited. - */ -@Deprecated("This patch only works with an outdated app target that is no longer fully supported by Facebook.") -@Suppress("unused") -val disableSwitchingEmojiToStickerPatch = bytecodePatch( - description = "Disables switching from emoji to sticker search mode in message input field.", -) { - compatibleWith("com.facebook.orca"("439.0.0.29.119")) - - execute { - switchMessengeInputEmojiButtonFingerprint.method.apply { - val setStringIndex = switchMessengeInputEmojiButtonFingerprint.patternMatch!!.startIndex + 2 - val targetRegister = getInstruction(setStringIndex).registerA - - replaceInstruction(setStringIndex, "const-string v$targetRegister, \"expression\"") - } - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/messenger/inputfield/DisableTypingIndicatorPatch.kt b/patches/src/main/kotlin/app/revanced/patches/messenger/inputfield/DisableTypingIndicatorPatch.kt deleted file mode 100644 index 0d5bfd58c..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/messenger/inputfield/DisableTypingIndicatorPatch.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.messenger.inputfield - -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction -import app.revanced.patcher.patch.bytecodePatch - -@Suppress("unused") -val disableTypingIndicatorPatch = bytecodePatch( - name = "Disable typing indicator", - description = "Disables the indicator while typing a message.", -) { - compatibleWith("com.facebook.orca") - - execute { - sendTypingIndicatorFingerprint.method.replaceInstruction(0, "return-void") - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/messenger/inputfield/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/messenger/inputfield/Fingerprints.kt deleted file mode 100644 index 75fd54f7d..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/messenger/inputfield/Fingerprints.kt +++ /dev/null @@ -1,31 +0,0 @@ -package app.revanced.patches.messenger.inputfield - -import app.revanced.patcher.fingerprint -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.dexbacked.value.DexBackedStringEncodedValue - -internal val sendTypingIndicatorFingerprint = fingerprint { - returns("V") - parameters() - custom { method, classDef -> - method.name == "run" && - classDef.fields.any { - it.name == "__redex_internal_original_name" && - (it.initialValue as? DexBackedStringEncodedValue)?.value == "ConversationTypingContext\$sendActiveStateRunnable\$1" - } - } -} - -internal val switchMessengeInputEmojiButtonFingerprint = fingerprint { - returns("V") - parameters("L", "Z") - opcodes( - Opcode.IGET_OBJECT, - Opcode.IF_EQZ, - Opcode.CONST_STRING, - Opcode.GOTO, - Opcode.CONST_STRING, - Opcode.GOTO, - ) - strings("afterTextChanged", "expression_search") -} diff --git a/patches/src/main/kotlin/app/revanced/patches/messenger/layout/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/messenger/layout/Fingerprints.kt index 2abc12367..0abc4deed 100644 --- a/patches/src/main/kotlin/app/revanced/patches/messenger/layout/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/messenger/layout/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.messenger.layout import app.revanced.patcher.fingerprint -internal val isFacebookButtonEnabledFingerprint = fingerprint { +internal val isFacebookButtonEnabledFingerprint by fingerprint { parameters() returns("Z") strings("FacebookButtonTabButtonImplementation") diff --git a/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/Fingerprints.kt index b8dd008e4..414dac30c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.messenger.metaai import com.android.tools.smali.dexlib2.Opcode import app.revanced.patcher.fingerprint -internal val getMobileConfigBoolFingerprint = fingerprint { +internal val getMobileConfigBoolFingerprint by fingerprint { parameters("J") returns("Z") opcodes(Opcode.RETURN) @@ -12,12 +12,12 @@ internal val getMobileConfigBoolFingerprint = fingerprint { } } -internal val metaAIKillSwitchCheckFingerprint = fingerprint { - strings("SearchAiagentImplementationsKillSwitch") +internal val metaAIKillSwitchCheckFingerprint by fingerprint { opcodes(Opcode.CONST_WIDE) + strings("SearchAiagentImplementationsKillSwitch") } -internal val extensionMethodFingerprint = fingerprint { +internal val extensionMethodFingerprint by fingerprint { strings("REPLACED_BY_PATCH") custom { method, classDef -> method.name == EXTENSION_METHOD_NAME && classDef.type == EXTENSION_CLASS_DESCRIPTOR diff --git a/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/RemoveMetaAIPatch.kt b/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/RemoveMetaAIPatch.kt index adee83a30..37d13e3dc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/RemoveMetaAIPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/messenger/metaai/RemoveMetaAIPatch.kt @@ -36,7 +36,7 @@ val removeMetaAIPatch = bytecodePatch( // Extract the common starting digits of Meta AI flag IDs from a flag found in code. val relevantDigits = with(metaAIKillSwitchCheckFingerprint) { - method.getInstruction(patternMatch!!.startIndex).wideLiteral + method.getInstruction(patternMatch.startIndex).wideLiteral }.toString().substring(0, 7) // Replace placeholder in the extension method. diff --git a/patches/src/main/kotlin/app/revanced/patches/messenger/navbar/RemoveMetaAITabPatch.kt b/patches/src/main/kotlin/app/revanced/patches/messenger/navbar/RemoveMetaAITabPatch.kt deleted file mode 100644 index 280f448b3..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/messenger/navbar/RemoveMetaAITabPatch.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.messenger.navbar - -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.messenger.metaai.removeMetaAIPatch - -@Deprecated("Superseded by removeMetaAIPatch", ReplaceWith("removeMetaAIPatch")) -@Suppress("unused") -val removeMetaAITabPatch = bytecodePatch( - description = "Removes the 'Meta AI' tab from the navbar.", -) { - dependsOn(removeMetaAIPatch) -} diff --git a/patches/src/main/kotlin/app/revanced/patches/meta/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/meta/ads/Fingerprints.kt index d9e1d9e0b..a2aca9ef3 100644 --- a/patches/src/main/kotlin/app/revanced/patches/meta/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/meta/ads/Fingerprints.kt @@ -1,13 +1,13 @@ -package app.revanced.patches.meta.ads - -import app.revanced.patcher.fingerprint -import com.android.tools.smali.dexlib2.AccessFlags - -internal val adInjectorFingerprint = fingerprint { - accessFlags(AccessFlags.PRIVATE) - returns("Z") - parameters("L", "L") - strings( - "SponsoredContentController.insertItem", - ) -} +package app.revanced.patches.meta.ads + +import app.revanced.patcher.fingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal val adInjectorFingerprint by fingerprint { + accessFlags(AccessFlags.PRIVATE) + returns("Z") + parameters("L", "L") + strings( + "SponsoredContentController.insertItem", + ) +} diff --git a/patches/src/main/kotlin/app/revanced/patches/meta/ads/HideAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/meta/ads/HideAdsPatch.kt deleted file mode 100644 index 9c6839f6c..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/meta/ads/HideAdsPatch.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.meta.ads - -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.util.returnEarly - -@Deprecated("Instead use the Instagram or Threads specific hide ads patch") -@Suppress("unused") -val hideAdsPatch = bytecodePatch { - execute { - adInjectorFingerprint.method.returnEarly(false) - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/locale/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/locale/Fingerprints.kt index 14105f762..021e320fc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/locale/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/locale/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.mifitness.misc.locale import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode -internal val syncBluetoothLanguageFingerprint = fingerprint { +internal val syncBluetoothLanguageFingerprint by fingerprint { opcodes(Opcode.MOVE_RESULT_OBJECT) custom { method, _ -> method.name == "syncBluetoothLanguage" && diff --git a/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/locale/ForceEnglishLocalePatch.kt b/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/locale/ForceEnglishLocalePatch.kt index a2a53caba..676df651e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/locale/ForceEnglishLocalePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/locale/ForceEnglishLocalePatch.kt @@ -17,7 +17,7 @@ val forceEnglishLocalePatch = bytecodePatch( execute { syncBluetoothLanguageFingerprint.method.apply { - val resolvePhoneLocaleInstruction = syncBluetoothLanguageFingerprint.patternMatch!!.startIndex + val resolvePhoneLocaleInstruction = syncBluetoothLanguageFingerprint.instructionMatches.first().index val registerIndexToUpdate = getInstruction(resolvePhoneLocaleInstruction).registerA replaceInstruction( diff --git a/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/login/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/login/Fingerprints.kt index e3eee2499..d3083e8fb 100644 --- a/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/login/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/mifitness/misc/login/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.mifitness.misc.login import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val xiaomiAccountManagerConstructorFingerprint = fingerprint { +internal val xiaomiAccountManagerConstructorFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.CONSTRUCTOR) parameters("Landroid/content/Context;", "Z") custom { method, _ -> diff --git a/patches/src/main/kotlin/app/revanced/patches/music/ad/video/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/ad/video/Fingerprints.kt index 6ce0519ad..202a2d889 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/ad/video/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/ad/video/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.music.ad.video import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode -internal val showVideoAdsParentFingerprint = fingerprint { +internal val showVideoAdsParentFingerprint by fingerprint { opcodes( Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_VIRTUAL, diff --git a/patches/src/main/kotlin/app/revanced/patches/music/ad/video/HideVideoAds.kt b/patches/src/main/kotlin/app/revanced/patches/music/ad/video/HideVideoAds.kt index 27c981256..445dc02fd 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/ad/video/HideVideoAds.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/ad/video/HideVideoAds.kt @@ -12,7 +12,7 @@ val hideVideoAdsPatch = bytecodePatch( execute { navigate(showVideoAdsParentFingerprint.originalMethod) - .to(showVideoAdsParentFingerprint.patternMatch!!.startIndex + 1) + .to(showVideoAdsParentFingerprint.instructionMatches.first().index + 1) .stop() .addInstruction(0, "const/4 p1, 0x0") } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/Fingerprints.kt index 4ac10dd9b..0883a218f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val allowExclusiveAudioPlaybackFingerprint = fingerprint { +internal val allowExclusiveAudioPlaybackFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentrepeat/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentrepeat/Fingerprints.kt index 13820d29d..4ede1cadc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentrepeat/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentrepeat/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val repeatTrackFingerprint = fingerprint { +internal val repeatTrackFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L", "L") diff --git a/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentrepeat/PermanentRepeatPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentrepeat/PermanentRepeatPatch.kt index cbcf83c5d..962eaa36c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentrepeat/PermanentRepeatPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentrepeat/PermanentRepeatPatch.kt @@ -14,7 +14,7 @@ val permanentRepeatPatch = bytecodePatch( compatibleWith("com.google.android.apps.youtube.music") execute { - val startIndex = repeatTrackFingerprint.patternMatch!!.endIndex + val startIndex = repeatTrackFingerprint.instructionMatches.last().index val repeatIndex = startIndex + 1 repeatTrackFingerprint.method.apply { diff --git a/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentshuffle/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentshuffle/Fingerprints.kt deleted file mode 100644 index f2169744f..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentshuffle/Fingerprints.kt +++ /dev/null @@ -1,19 +0,0 @@ -package app.revanced.patches.music.interaction.permanentshuffle - -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.AccessFlags -import app.revanced.patcher.fingerprint - -internal val disableShuffleFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("V") - parameters() - opcodes( - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.SGET_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL - ) -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentshuffle/PermanentShufflePatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentshuffle/PermanentShufflePatch.kt deleted file mode 100644 index 1e4d81d3d..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/music/interaction/permanentshuffle/PermanentShufflePatch.kt +++ /dev/null @@ -1,17 +0,0 @@ -package app.revanced.patches.music.interaction.permanentshuffle - -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated("This patch no longer works and will be removed in the future.") -@Suppress("unused") -val permanentShufflePatch = bytecodePatch( - description = "Permanently remember your shuffle preference " + - "even if the playlist ends or another track is played." -) { - compatibleWith("com.google.android.apps.youtube.music") - - execute { - disableShuffleFingerprint.method.addInstruction(0, "return-void") - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/Fingerprints.kt index 234078c2a..2cefcc63c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/Fingerprints.kt @@ -4,9 +4,8 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val constructCategoryBarFingerprint = fingerprint { +internal val constructCategoryBarFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") parameters("Landroid/content/Context;", "L", "L", "L") opcodes( Opcode.IPUT_OBJECT, diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/HideCategoryBar.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/HideCategoryBar.kt index 2128722e7..c22a44b43 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/HideCategoryBar.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/compactheader/HideCategoryBar.kt @@ -16,7 +16,7 @@ val hideCategoryBar = bytecodePatch( execute { constructCategoryBarFingerprint.method.apply { - val insertIndex = constructCategoryBarFingerprint.patternMatch!!.startIndex + val insertIndex = constructCategoryBarFingerprint.instructionMatches.first().index val register = getInstruction(insertIndex - 1).registerA val freeRegister = findFreeRegister(insertIndex, register) diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/premium/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/premium/Fingerprints.kt index 29558ab4b..42dbc6bcb 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/premium/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/premium/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val hideGetPremiumFingerprint = fingerprint { +internal val hideGetPremiumFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters() @@ -16,7 +16,7 @@ internal val hideGetPremiumFingerprint = fingerprint { strings("FEmusic_history", "FEmusic_offline") } -internal val membershipSettingsFingerprint = fingerprint { +internal val membershipSettingsFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/CharSequence;") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/premium/HideGetPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/premium/HideGetPremiumPatch.kt index 23965cea4..ce723b9dc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/premium/HideGetPremiumPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/premium/HideGetPremiumPatch.kt @@ -15,7 +15,7 @@ val hideGetPremiumPatch = bytecodePatch( execute { hideGetPremiumFingerprint.method.apply { - val insertIndex = hideGetPremiumFingerprint.patternMatch!!.endIndex + val insertIndex = hideGetPremiumFingerprint.instructionMatches.last().index val setVisibilityInstruction = getInstruction(insertIndex) val getPremiumViewRegister = setVisibilityInstruction.registerC diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/Fingerprints.kt index f3c96dc44..7012360a5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/Fingerprints.kt @@ -4,9 +4,8 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val pivotBarConstructorFingerprint = fingerprint { +internal val pivotBarConstructorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") parameters("L", "Z") opcodes( Opcode.CHECK_CAST, diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/RemoveUpgradeButtonPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/RemoveUpgradeButtonPatch.kt index 22878b05f..b1fb8ed9f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/RemoveUpgradeButtonPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/RemoveUpgradeButtonPatch.kt @@ -23,7 +23,7 @@ val removeUpgradeButtonPatch = bytecodePatch( execute { pivotBarConstructorFingerprint.method.apply { val pivotBarElementFieldReference = - getInstruction(pivotBarConstructorFingerprint.patternMatch!!.endIndex - 1) + getInstruction(pivotBarConstructorFingerprint.instructionMatches.last().index - 1) .getReference() val register = getInstruction(0).registerC @@ -37,7 +37,7 @@ val removeUpgradeButtonPatch = bytecodePatch( iput-object v0, v$register, $pivotBarElementFieldReference """.toInstructions().toMutableList() - val endIndex = pivotBarConstructorFingerprint.patternMatch!!.endIndex + val endIndex = pivotBarConstructorFingerprint.instructionMatches.last().index // Replace the instruction to retain the label at given index. replaceInstruction( diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/androidauto/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/androidauto/Fingerprints.kt index 97dea5650..30c0ec0cb 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/androidauto/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/androidauto/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.music.misc.androidauto import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val checkCertificateFingerprint = fingerprint { +internal val checkCertificateFingerprint by fingerprint { returns("Z") parameters("Ljava/lang/String;") strings( diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/backgroundplayback/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/backgroundplayback/Fingerprints.kt index e1cf24e1a..7e408aaa9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/backgroundplayback/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/backgroundplayback/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val backgroundPlaybackDisableFingerprint = fingerprint { +internal val backgroundPlaybackDisableFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Z") parameters("L") @@ -21,7 +21,7 @@ internal val backgroundPlaybackDisableFingerprint = fingerprint { ) } -internal val kidsBackgroundPlaybackPolicyControllerFingerprint = fingerprint { +internal val kidsBackgroundPlaybackPolicyControllerFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("I", "L", "Z") diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/hooks/ApplicationInitHook.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/hooks/ApplicationInitHook.kt index 1e1a43f9a..869174c45 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/hooks/ApplicationInitHook.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/extension/hooks/ApplicationInitHook.kt @@ -1,10 +1,13 @@ package app.revanced.patches.music.misc.extension.hooks +import app.revanced.patcher.string import app.revanced.patches.shared.misc.extension.extensionHook internal val applicationInitHook = extensionHook { returns("V") parameters() - strings("activity") + instructions( + string("activity") + ) custom { method, _ -> method.name == "onCreate" } } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/gms/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/gms/Fingerprints.kt index 7131e143d..9ad55f01d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/gms/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/gms/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.music.misc.gms import app.revanced.patcher.fingerprint -internal val musicActivityOnCreateFingerprint = fingerprint { +internal val musicActivityOnCreateFingerprint by fingerprint { returns("V") parameters("Landroid/os/Bundle;") custom { method, classDef -> diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/Fingerprints.kt index abf19cc95..22cf63b84 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val playerRequestConstructorFingerprint = fingerprint { +internal val playerRequestConstructorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) strings("player") } @@ -12,7 +12,7 @@ internal val playerRequestConstructorFingerprint = fingerprint { /** * Matches using the class found in [playerRequestConstructorFingerprint]. */ -internal val createPlayerRequestBodyFingerprint = fingerprint { +internal val createPlayerRequestBodyFingerprint by fingerprint { parameters("L") returns("V") opcodes( @@ -26,7 +26,7 @@ internal val createPlayerRequestBodyFingerprint = fingerprint { /** * Used to get a reference to other clientInfo fields. */ -internal val setClientInfoFieldsFingerprint = fingerprint { +internal val setClientInfoFieldsFingerprint by fingerprint { returns("L") strings("Google Inc.") } @@ -34,6 +34,6 @@ internal val setClientInfoFieldsFingerprint = fingerprint { /** * Used to get a reference to the clientInfo and clientInfo.clientVersion field. */ -internal val setClientInfoClientVersionFingerprint = fingerprint { +internal val setClientInfoClientVersionFingerprint by fingerprint { strings("10.29") } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofClientPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofClientPatch.kt index f34797f03..1997f084e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofClientPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofClientPatch.kt @@ -39,7 +39,7 @@ val spoofClientPatch = bytecodePatch( val createPlayerRequestBodyMatch = createPlayerRequestBodyFingerprint.match(playerRequestClass) val clientInfoContainerClass = createPlayerRequestBodyMatch.method - .getInstruction(createPlayerRequestBodyMatch.patternMatch!!.startIndex) + .getInstruction(createPlayerRequestBodyMatch.instructionMatches.first().index) .getReference()!!.type val clientInfoField = setClientInfoClientVersionFingerprint.method.instructions.first { @@ -56,7 +56,7 @@ val spoofClientPatch = bytecodePatch( val clientModelField = setClientInfoFieldInstructions[5] val osVersionField = setClientInfoFieldInstructions[7] val clientVersionField = setClientInfoClientVersionFingerprint.method - .getInstruction(setClientInfoClientVersionFingerprint.stringMatches!!.first().index + 1) + .getInstruction(setClientInfoClientVersionFingerprint.stringMatches.first().index + 1) .getReference() // Helper method to spoof the client info. @@ -96,7 +96,7 @@ val spoofClientPatch = bytecodePatch( } createPlayerRequestBodyMatch.method.apply { - val checkCastIndex = createPlayerRequestBodyMatch.patternMatch!!.startIndex + val checkCastIndex = createPlayerRequestBodyMatch.instructionMatches.first().index val clientInfoContainerRegister = getInstruction(checkCastIndex).registerA addInstruction(checkCastIndex + 1, "invoke-static {v$clientInfoContainerRegister}, $spoofClientInfoMethod") diff --git a/patches/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/Fingerprints.kt index 6bc4c21e5..a118f681a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.myexpenses.misc.pro import app.revanced.patcher.fingerprint -internal val isEnabledFingerprint = fingerprint { +internal val isEnabledFingerprint by fingerprint { returns("Z") strings("feature", "feature.licenceStatus") } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/Fingerprints.kt index 160e2db27..6afea3462 100644 --- a/patches/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/Fingerprints.kt @@ -3,14 +3,14 @@ package app.revanced.patches.myfitnesspal.ads import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val isPremiumUseCaseImplFingerprint = fingerprint { +internal val isPremiumUseCaseImplFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) custom { method, classDef -> classDef.endsWith("IsPremiumUseCaseImpl;") && method.name == "doWork" } } -internal val mainActivityNavigateToNativePremiumUpsellFingerprint = fingerprint { +internal val mainActivityNavigateToNativePremiumUpsellFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returns("V") custom { method, classDef -> diff --git a/patches/src/main/kotlin/app/revanced/patches/nfctoolsse/misc/pro/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/nfctoolsse/misc/pro/Fingerprints.kt deleted file mode 100644 index a185aca8f..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/nfctoolsse/misc/pro/Fingerprints.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.nfctoolsse.misc.pro - -import com.android.tools.smali.dexlib2.AccessFlags -import app.revanced.patcher.fingerprint - -@Deprecated("This patch no longer works and will soon be deleted.") -internal val isLicenseRegisteredFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC) - returns("Z") - strings("kLicenseCheck") -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/nfctoolsse/misc/pro/UnlockProPatch.kt b/patches/src/main/kotlin/app/revanced/patches/nfctoolsse/misc/pro/UnlockProPatch.kt deleted file mode 100644 index ac3ac09af..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/nfctoolsse/misc/pro/UnlockProPatch.kt +++ /dev/null @@ -1,20 +0,0 @@ -package app.revanced.patches.nfctoolsse.misc.pro - -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.patch.bytecodePatch - -@Suppress("unused") -@Deprecated("This patch no longer works and will soon be deleted.") -val unlockProPatch = bytecodePatch{ - compatibleWith("com.wakdev.apps.nfctools.se") - - execute { - isLicenseRegisteredFingerprint.method.addInstructions( - 0, - """ - const/4 v0, 0x1 - return v0 - """, - ) - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/nunl/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/nunl/ads/Fingerprints.kt index 109b973e0..403955806 100644 --- a/patches/src/main/kotlin/app/revanced/patches/nunl/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/nunl/ads/Fingerprints.kt @@ -4,14 +4,14 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val jwPlayerConfigFingerprint = fingerprint { +internal val jwPlayerConfigFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) custom { methodDef, classDef -> classDef.type == "Lcom/jwplayer/pub/api/configuration/PlayerConfig${'$'}Builder;" && methodDef.name == "advertisingConfig" } } -internal val screenMapperFingerprint = fingerprint { +internal val screenMapperFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Lnl/nu/android/bff/domain/models/screen/ScreenEntity;") parameters("Lnl/nu/performance/api/client/objects/Screen;") @@ -27,7 +27,7 @@ internal val screenMapperFingerprint = fingerprint { } } -internal val nextPageRepositoryImplFingerprint = fingerprint { +internal val nextPageRepositoryImplFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returns("Lnl/nu/android/bff/domain/models/Page;") parameters("Lnl/nu/performance/api/client/PacResponse;", "Ljava/lang/String;") diff --git a/patches/src/main/kotlin/app/revanced/patches/nunl/firebase/SpoofCertificatePatch.kt b/patches/src/main/kotlin/app/revanced/patches/nunl/firebase/SpoofCertificatePatch.kt index 65944c4c1..1e5890a85 100644 --- a/patches/src/main/kotlin/app/revanced/patches/nunl/firebase/SpoofCertificatePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/nunl/firebase/SpoofCertificatePatch.kt @@ -11,7 +11,9 @@ val spoofCertificatePatch = bytecodePatch( compatibleWith("nl.sanomamedia.android.nu") execute { - getFingerprintHashForPackageFingerprints.forEach { fingerprint -> + getFingerprintHashForPackageFingerprints.forEach { fingerprintBuilder -> + val fingerprint by fingerprintBuilder + fingerprint.method.returnEarly("eae41fc018df2731a9b6ae1ac327da44a288667b") } } diff --git a/patches/src/main/kotlin/app/revanced/patches/nyx/misc/pro/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/nyx/misc/pro/Fingerprints.kt deleted file mode 100644 index e2bffa451..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/nyx/misc/pro/Fingerprints.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.nyx.misc.pro - -import app.revanced.patcher.fingerprint - -internal val checkProFingerprint = fingerprint { - custom { method, classDef -> - classDef.endsWith("BillingManager;") && method.name == "isProVersion" - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/nyx/misc/pro/UnlockProPatch.kt b/patches/src/main/kotlin/app/revanced/patches/nyx/misc/pro/UnlockProPatch.kt deleted file mode 100644 index 179e745e0..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/nyx/misc/pro/UnlockProPatch.kt +++ /dev/null @@ -1,20 +0,0 @@ -package app.revanced.patches.nyx.misc.pro - -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated("This patch will be removed in the future.") -@Suppress("unused") -val unlockProPatch = bytecodePatch { - compatibleWith("com.awedea.nyx") - - execute { - checkProFingerprint.method.addInstructions( - 0, - """ - const/4 v0, 0x1 - return v0 - """, - ) - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/openinghours/misc/fix/crash/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/openinghours/misc/fix/crash/Fingerprints.kt index 69463c510..56fcf73d7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/openinghours/misc/fix/crash/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/openinghours/misc/fix/crash/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.openinghours.misc.fix.crash import app.revanced.patcher.fingerprint -internal val setPlaceFingerprint = fingerprint { +internal val setPlaceFingerprint by fingerprint { returns("V") parameters("Lde/simon/openinghours/models/Place;") custom { method, _ -> diff --git a/patches/src/main/kotlin/app/revanced/patches/orfon/detection/root/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/orfon/detection/root/Fingerprints.kt index 525d4f37d..868138661 100644 --- a/patches/src/main/kotlin/app/revanced/patches/orfon/detection/root/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/orfon/detection/root/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.orfon.detection.root import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val isDeviceRootedFingeprint = fingerprint { +internal val isDeviceRootedFingeprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("Z") custom { method, classDef -> diff --git a/patches/src/main/kotlin/app/revanced/patches/pandora/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/pandora/ads/Fingerprints.kt index e3f432e16..9e0a80147 100644 --- a/patches/src/main/kotlin/app/revanced/patches/pandora/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/pandora/ads/Fingerprints.kt @@ -2,13 +2,13 @@ package app.revanced.patches.pandora.ads import app.revanced.patcher.fingerprint -internal val getIsAdSupportedFingerprint = fingerprint { +internal val getIsAdSupportedFingerprint by fingerprint { custom { method, classDef -> method.name == "getIsAdSupported" && classDef.endsWith("UserData;") } } -internal val requestAudioAdFingerprint = fingerprint { +internal val requestAudioAdFingerprint by fingerprint { custom { method, classDef -> method.name == "requestAudioAdFromAdSDK" && classDef.endsWith("ContentServiceOpsImpl;") } diff --git a/patches/src/main/kotlin/app/revanced/patches/pandora/misc/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/pandora/misc/Fingerprints.kt index 2a14e0ed1..4c6e675fc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/pandora/misc/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/pandora/misc/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.pandora.misc import app.revanced.patcher.fingerprint -internal val skipLimitBehaviorFingerprint = fingerprint { +internal val skipLimitBehaviorFingerprint by fingerprint { custom { method, classDef -> method.name == "getSkipLimitBehavior" && classDef.endsWith("UserData;") } diff --git a/patches/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/Fingerprints.kt index 90c0bbb91..d37351f8e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.photomath.detection.deviceid import com.android.tools.smali.dexlib2.Opcode import app.revanced.patcher.fingerprint -internal val getDeviceIdFingerprint = fingerprint { +internal val getDeviceIdFingerprint by fingerprint { returns("Ljava/lang/String;") parameters() opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/Fingerprints.kt index c6563270e..d1b24e554 100644 --- a/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.photomath.detection.signature import com.android.tools.smali.dexlib2.Opcode import app.revanced.patcher.fingerprint -internal val checkSignatureFingerprint = fingerprint { +internal val checkSignatureFingerprint by fingerprint { opcodes( Opcode.CONST_STRING, Opcode.INVOKE_STATIC, diff --git a/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/SignatureDetectionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/SignatureDetectionPatch.kt index 00b47e516..96eb3ba0f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/SignatureDetectionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/photomath/detection/signature/SignatureDetectionPatch.kt @@ -10,7 +10,7 @@ val signatureDetectionPatch = bytecodePatch( ) { execute { - val replacementIndex = checkSignatureFingerprint.patternMatch!!.endIndex + val replacementIndex = checkSignatureFingerprint.instructionMatches.last().index val checkRegister = checkSignatureFingerprint.method.getInstruction(replacementIndex).registerA checkSignatureFingerprint.method.replaceInstruction(replacementIndex, "const/4 v$checkRegister, 0x1") diff --git a/patches/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/Fingerprints.kt index 301f2f9a5..694573b43 100644 --- a/patches/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val hideUpdatePopupFingerprint = fingerprint { +internal val hideUpdatePopupFingerprint by fingerprint { accessFlags(AccessFlags.FINAL, AccessFlags.PUBLIC) returns("V") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/Fingerprints.kt index 6722f4223..d0565792d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.photomath.misc.unlock.bookpoint import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val isBookpointEnabledFingerprint = fingerprint { +internal val isBookpointEnabledFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/Fingerprints.kt index f6c282cbd..bc153d400 100644 --- a/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.photomath.misc.unlock.plus import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val isPlusUnlockedFingerprint = fingerprint{ +internal val isPlusUnlockedFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") strings("genius") diff --git a/patches/src/main/kotlin/app/revanced/patches/piccomafr/misc/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/piccomafr/misc/Fingerprints.kt index 8c2d579ef..199cd01af 100644 --- a/patches/src/main/kotlin/app/revanced/patches/piccomafr/misc/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/piccomafr/misc/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.piccomafr.misc import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val getAndroidIdFingerprint = fingerprint { +internal val getAndroidIdFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/String;") parameters("Landroid/content/Context;") diff --git a/patches/src/main/kotlin/app/revanced/patches/piccomafr/tracking/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/piccomafr/tracking/Fingerprints.kt index 794f21bcb..e757223dd 100644 --- a/patches/src/main/kotlin/app/revanced/patches/piccomafr/tracking/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/piccomafr/tracking/Fingerprints.kt @@ -3,19 +3,18 @@ package app.revanced.patches.piccomafr.tracking import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val appMeasurementFingerprint = fingerprint { +internal val appMeasurementFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returns("V") strings("config/app/", "Fetching remote configuration") } -internal val facebookSDKFingerprint = fingerprint { +internal val facebookSDKFingerprint by fingerprint { accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) - returns("V") strings("instagram.com", "facebook.com") } -internal val firebaseInstallFingerprint = fingerprint { +internal val firebaseInstallFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE) strings( "https://%s/%s/%s", diff --git a/patches/src/main/kotlin/app/revanced/patches/pixiv/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/pixiv/ads/Fingerprints.kt index 3e2addaa0..825a834b6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/pixiv/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/pixiv/ads/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.pixiv.ads import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val shouldShowAdsFingerprint = fingerprint { +internal val shouldShowAdsFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") custom { methodDef, classDef -> diff --git a/patches/src/main/kotlin/app/revanced/patches/primevideo/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/primevideo/ads/Fingerprints.kt index ac3a1c43a..8af0fc273 100644 --- a/patches/src/main/kotlin/app/revanced/patches/primevideo/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/primevideo/ads/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val enterServerInsertedAdBreakStateFingerprint = fingerprint { +internal val enterServerInsertedAdBreakStateFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) parameters("Lcom/amazon/avod/fsm/Trigger;") returns("V") @@ -19,7 +19,7 @@ internal val enterServerInsertedAdBreakStateFingerprint = fingerprint { } } -internal val doTriggerFingerprint = fingerprint { +internal val doTriggerFingerprint by fingerprint { accessFlags(AccessFlags.PROTECTED) returns("V") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/primevideo/video/speed/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/primevideo/video/speed/Fingerprints.kt index bd4431d56..4f02360fe 100644 --- a/patches/src/main/kotlin/app/revanced/patches/primevideo/video/speed/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/primevideo/video/speed/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.primevideo.video.speed import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val playbackUserControlsInitializeFingerprint = fingerprint { +internal val playbackUserControlsInitializeFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) parameters("Lcom/amazon/avod/playbackclient/PlaybackInitializationContext;") returns("V") @@ -12,7 +12,7 @@ internal val playbackUserControlsInitializeFingerprint = fingerprint { } } -internal val playbackUserControlsPrepareForPlaybackFingerprint = fingerprint { +internal val playbackUserControlsPrepareForPlaybackFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) parameters("Lcom/amazon/avod/playbackclient/PlaybackContext;") returns("V") diff --git a/patches/src/main/kotlin/app/revanced/patches/rar/misc/annoyances/purchasereminder/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/rar/misc/annoyances/purchasereminder/Fingerprints.kt index a4d2c9e22..d63bbce86 100644 --- a/patches/src/main/kotlin/app/revanced/patches/rar/misc/annoyances/purchasereminder/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/rar/misc/annoyances/purchasereminder/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.rar.misc.annoyances.purchasereminder import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val showReminderFingerprint = fingerprint { +internal val showReminderFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("V") custom { method, _ -> diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/ad/comments/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/ad/comments/Fingerprints.kt index c99df5707..91ea04763 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/ad/comments/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/ad/comments/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.reddit.ad.comments import app.revanced.patcher.fingerprint -internal val hideCommentAdsFingerprint = fingerprint { +internal val hideCommentAdsFingerprint by fingerprint { strings( "link", // CommentPageRepository is not returning a link object diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/ad/general/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/ad/general/Fingerprints.kt index e7dd78912..93310ce7e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/ad/general/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/ad/general/Fingerprints.kt @@ -3,14 +3,14 @@ package app.revanced.patches.reddit.ad.general import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode -internal val adPostFingerprint = fingerprint { +internal val adPostFingerprint by fingerprint { returns("V") // "children" are present throughout multiple versions strings("children") custom { _, classDef -> classDef.endsWith("Listing;") } } -internal val newAdPostFingerprint = fingerprint { +internal val newAdPostFingerprint by fingerprint { opcodes(Opcode.INVOKE_VIRTUAL) strings("chain", "feedElement") custom { _, classDef -> classDef.sourceFile == "AdElementConverter.kt" } diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/Fingerprints.kt index bb87c2114..b3c0a957b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/Fingerprints.kt @@ -2,10 +2,10 @@ package app.revanced.patches.reddit.customclients.baconreader.api import app.revanced.patcher.fingerprint -internal val getAuthorizationUrlFingerprint = fingerprint { +internal val getAuthorizationUrlFingerprint by fingerprint { strings("client_id=zACVn0dSFGdWqQ") } -internal val getClientIdFingerprint = fingerprint { +internal val getClientIdFingerprint by fingerprint { strings("client_id=zACVn0dSFGdWqQ") custom { method, classDef -> if (!classDef.endsWith("RedditOAuth;")) return@custom false @@ -14,6 +14,6 @@ internal val getClientIdFingerprint = fingerprint { } } -internal val requestTokenFingerprint = fingerprint { +internal val requestTokenFingerprint by fingerprint { strings("zACVn0dSFGdWqQ", "kDm2tYpu9DqyWFFyPlNcXGEni4k") // App ID and secret. } diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/fix/redgifs/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/fix/redgifs/Fingerprints.kt index 524beeea0..82734e0b1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/fix/redgifs/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/fix/redgifs/Fingerprints.kt @@ -1,13 +1,11 @@ package app.revanced.patches.reddit.customclients.baconreader.fix.redgifs import app.revanced.patcher.fingerprint -import com.android.tools.smali.dexlib2.AccessFlags - -internal val getOkHttpClientFingerprint = fingerprint { +internal val getOkHttpClientFingerprint by fingerprint { returns("Lokhttp3/OkHttpClient;") parameters() custom { method, classDef -> classDef.type == "Lcom/onelouder/baconreader/media/gfycat/RedGifsManager;" && method.name == "getOkhttpClient" } -} +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/ads/Fingerprints.kt index 618e2f145..3462a9194 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/ads/Fingerprints.kt @@ -2,10 +2,10 @@ package app.revanced.patches.reddit.customclients.boostforreddit.ads import app.revanced.patcher.fingerprint -internal val maxMediationFingerprint = fingerprint { +internal val maxMediationFingerprint by fingerprint { strings("MaxMediation: Attempting to initialize SDK") } -internal val admobMediationFingerprint = fingerprint { +internal val admobMediationFingerprint by fingerprint { strings("AdmobMediation: Attempting to initialize SDK") } diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/Fingerprints.kt index cc06fd396..a6d454304 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/Fingerprints.kt @@ -2,11 +2,11 @@ package app.revanced.patches.reddit.customclients.boostforreddit.api import app.revanced.patcher.fingerprint -internal val buildUserAgentFingerprint = fingerprint { +internal val buildUserAgentFingerprint by fingerprint { strings("%s:%s:%s (by /u/%s)") } -internal val getClientIdFingerprint = fingerprint { +internal val getClientIdFingerprint by fingerprint { custom { method, classDef -> if (!classDef.endsWith("Credentials;")) return@custom false diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/Fingerprints.kt index a2b1530b8..f7a3ea815 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/Fingerprints.kt @@ -2,6 +2,6 @@ package app.revanced.patches.reddit.customclients.boostforreddit.fix.downloads import app.revanced.patcher.fingerprint -internal val downloadAudioFingerprint = fingerprint { +internal val downloadAudioFingerprint by fingerprint { strings("/DASH_audio.mp4", "/audio") } diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/FixAudioMissingInDownloadsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/FixAudioMissingInDownloadsPatch.kt index 8cb3f5518..c5b548f93 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/FixAudioMissingInDownloadsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/FixAudioMissingInDownloadsPatch.kt @@ -19,7 +19,7 @@ val fixAudioMissingInDownloadsPatch = bytecodePatch( ) downloadAudioFingerprint.method.apply { - downloadAudioFingerprint.stringMatches!!.forEach { match -> + downloadAudioFingerprint.stringMatches.forEach { match -> val replacement = endpointReplacements[match.string] val register = getInstruction(match.index).registerA diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/redgifs/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/redgifs/Fingerprints.kt index 1f3560d73..bbc71cba9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/redgifs/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/redgifs/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val createOkHttpClientFingerprint = fingerprint { +internal val createOkHttpClientFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE) opcodes( Opcode.NEW_INSTANCE, diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/Fingerprints.kt index 665dba5a4..e690af53d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/Fingerprints.kt @@ -3,14 +3,14 @@ package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val getOAuthAccessTokenFingerprint = fingerprint { +internal val getOAuthAccessTokenFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("Ljava/lang/String") strings("access_token") custom { method, _ -> method.definingClass == "Lnet/dean/jraw/http/oauth/OAuthData;" } } -internal val handleNavigationFingerprint = fingerprint { +internal val handleNavigationFingerprint by fingerprint { strings( "android.intent.action.SEARCH", "subscription", diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/api/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/api/Fingerprints.kt index 4bce1362c..0d7f124f6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/api/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/api/Fingerprints.kt @@ -2,6 +2,6 @@ package app.revanced.patches.reddit.customclients.infinityforreddit.api import app.revanced.patcher.fingerprint -internal val apiUtilsFingerprint = fingerprint { +internal val apiUtilsFingerprint by fingerprint { strings("native-lib") } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/subscription/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/subscription/Fingerprints.kt index 36fe06279..22842f81e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/subscription/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/subscription/Fingerprints.kt @@ -1,15 +1,14 @@ package app.revanced.patches.reddit.customclients.infinityforreddit.subscription import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal -internal val billingClientOnServiceConnectedFingerprint = fingerprint { +internal val billingClientOnServiceConnectedFingerprint by fingerprint { strings("Billing service connected") } -internal val startSubscriptionActivityFingerprint = fingerprint { - literal { - // Intent start flag only used in the subscription activity - 0x10008000 - } +internal val startSubscriptionActivityFingerprint by fingerprint { + instructions( + literal(0x10008000) // Intent start flag only used in the subscription activity + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/ads/Fingerprints.kt index 465faf120..e136d57ec 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/ads/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.reddit.customclients.joeyforreddit.ads import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val isAdFreeUserFingerprint = fingerprint { +internal val isAdFreeUserFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("Z") strings("AD_FREE_USER") diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/api/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/api/Fingerprints.kt index e6c591748..c6c5c0abb 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/api/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/api/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val authUtilityUserAgentFingerprint = fingerprint { +internal val authUtilityUserAgentFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Ljava/lang/String;") opcodes(Opcode.APUT_OBJECT) @@ -13,7 +13,7 @@ internal val authUtilityUserAgentFingerprint = fingerprint { } } -internal val getClientIdFingerprint = fingerprint { +internal val getClientIdFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("L") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/detection/piracy/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/detection/piracy/Fingerprints.kt index 76343a530..d8ae7417a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/detection/piracy/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/detection/piracy/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val piracyDetectionFingerprint = fingerprint { +internal val piracyDetectionFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returns("V") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/Fingerprints.kt index 5b3029094..8eb368f4c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/Fingerprints.kt @@ -1,6 +1,7 @@ package app.revanced.patches.reddit.customclients.redditisfun.api import app.revanced.patcher.fingerprint +import app.revanced.patcher.string import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode @@ -8,15 +9,15 @@ internal fun baseClientIdFingerprint(string: String) = fingerprint { strings("yyOCBp.RHJhDKd", string) } -internal val basicAuthorizationFingerprint = baseClientIdFingerprint( +internal val basicAuthorizationFingerprint by baseClientIdFingerprint( string = "fJOxVwBUyo*=f: - val clientIdIndex = fingerprint.stringMatches!!.first().index + val clientIdIndex = fingerprint.stringMatches.first().index fingerprint.method.apply { val clientIdRegister = getInstruction(clientIdIndex).registerA @@ -45,7 +45,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "dbrady://relay") { setRemoteConfigFingerprint.method.addInstructions(0, "return-void") // Prevent OAuth login being disabled remotely. - val checkIsOAuthRequestIndex = redditCheckDisableAPIFingerprint.patternMatch!!.startIndex + val checkIsOAuthRequestIndex = redditCheckDisableAPIFingerprint.instructionMatches.first().index redditCheckDisableAPIFingerprint.method.apply { val returnNextChain = getInstruction(checkIsOAuthRequestIndex).target diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/slide/api/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/slide/api/Fingerprints.kt index 4ff8be461..79f3179af 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/slide/api/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/slide/api/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.reddit.customclients.slide.api import app.revanced.patcher.fingerprint -internal val getClientIdFingerprint = fingerprint { +internal val getClientIdFingerprint by fingerprint { custom { method, classDef -> if (!classDef.endsWith("Credentials;")) return@custom false diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/ads/DisableAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/ads/DisableAdsPatch.kt index f210a6adb..738c6835a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/ads/DisableAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/ads/DisableAdsPatch.kt @@ -8,7 +8,7 @@ fun disableAdsPatch(block: BytecodePatchBuilder.() -> Unit = {}) = bytecodePatch name = "Disable ads", ) { execute { - isAdsEnabledFingerprint.method.returnEarly() + isAdsEnabledFingerprint.method.returnEarly(false) } block() diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/ads/Fingerprints.kt index e055493bd..0290c185b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/ads/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.reddit.customclients.sync.ads import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val isAdsEnabledFingerprint = fingerprint { +internal val isAdsEnabledFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Z") strings("SyncIapHelper") diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/detection/piracy/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/detection/piracy/Fingerprints.kt index e83e914d7..46a98af1a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/detection/piracy/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/detection/piracy/Fingerprints.kt @@ -7,7 +7,7 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.reference.Reference -internal val piracyDetectionFingerprint = fingerprint { +internal val piracyDetectionFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returns("V") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/annoyances/startup/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/annoyances/startup/Fingerprints.kt index 21c788a89..0e243f97c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/annoyances/startup/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/annoyances/startup/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.reddit.customclients.sync.syncforreddit.annoyances. import app.revanced.patcher.fingerprint -internal val mainActivityOnCreateFingerprint = fingerprint { +internal val mainActivityOnCreateFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("MainActivity;") && method.name == "onCreate" } diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/api/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/api/Fingerprints.kt index c7902b1f4..41e7d5f92 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/api/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/api/Fingerprints.kt @@ -2,18 +2,18 @@ package app.revanced.patches.reddit.customclients.sync.syncforreddit.api import app.revanced.patcher.fingerprint -internal val getAuthorizationStringFingerprint = fingerprint { +internal val getAuthorizationStringFingerprint by fingerprint { strings("authorize.compact?client_id") } -internal val getBearerTokenFingerprint = fingerprint { +internal val getBearerTokenFingerprint by fingerprint { strings("Basic") } -internal val getUserAgentFingerprint = fingerprint { +internal val getUserAgentFingerprint by fingerprint { strings("android:com.laurencedawson.reddit_sync") } -internal val imgurImageAPIFingerprint = fingerprint { +internal val imgurImageAPIFingerprint by fingerprint { strings("https://imgur-apiv3.p.rapidapi.com/3/image") } diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/api/SpoofClientPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/api/SpoofClientPatch.kt index 0246ce711..18c8cac7c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/api/SpoofClientPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/api/SpoofClientPatch.kt @@ -37,7 +37,7 @@ val spoofClientPatch = spoofClientPatch( returnEarly("Basic $auth") val occurrenceIndex = - getAuthorizationStringFingerprint.stringMatches!!.first().index + getAuthorizationStringFingerprint.stringMatches.first().index getAuthorizationStringFingerprint.method.apply { val authorizationStringInstruction = getInstruction(occurrenceIndex) @@ -71,7 +71,7 @@ val spoofClientPatch = spoofClientPatch( // region Patch Imgur API URL. imgurImageAPIFingerprint.let { - val apiUrlIndex = it.stringMatches!!.first().index + val apiUrlIndex = it.stringMatches.first().index it.method.replaceInstruction( apiUrlIndex, "const-string v1, \"https://api.imgur.com/3/image\"", diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/redgifs/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/redgifs/Fingerprints.kt index 16dfa4620..8c47e97a6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/redgifs/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/redgifs/Fingerprints.kt @@ -2,6 +2,7 @@ package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.redgifs import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.fingerprint +import app.revanced.patcher.opcode import app.revanced.util.indexOfFirstInstruction import app.revanced.util.writeRegister import com.android.tools.smali.dexlib2.AccessFlags @@ -9,7 +10,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction11n -internal val createOkHttpClientFingerprint = fingerprint { +internal val createOkHttpClientFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returns("V") parameters() @@ -25,13 +26,13 @@ internal val createOkHttpClientFingerprint = fingerprint { } } -internal val getDefaultUserAgentFingerprint = fingerprint { +internal val getDefaultUserAgentFingerprint by fingerprint { custom { method, classDef -> method.name == "getDefaultUserAgent" && classDef.type == EXTENSION_CLASS_DESCRIPTOR } } -internal val getOriginalUserAgentFingerprint = fingerprint { +internal val getOriginalUserAgentFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Ljava/lang/String;") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/slink/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/slink/Fingerprints.kt index f7287fcc3..641a3e99e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/slink/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/slink/Fingerprints.kt @@ -2,11 +2,11 @@ package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.slink import app.revanced.patcher.fingerprint -internal val linkHelperOpenLinkFingerprint = fingerprint { +internal val linkHelperOpenLinkFingerprint by fingerprint { strings("Link title: ") } -internal val setAuthorizationHeaderFingerprint = fingerprint { +internal val setAuthorizationHeaderFingerprint by fingerprint { returns("Ljava/util/HashMap;") strings("Authorization", "bearer ") custom { method, _ -> method.definingClass == "Lcom/laurencedawson/reddit_sync/singleton/a;" } diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/thumbnail/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/thumbnail/Fingerprints.kt index 7a64031f1..6ed3118cb 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/thumbnail/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/thumbnail/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.thumbna import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val customImageViewLoadFingerprint = fingerprint { +internal val customImageViewLoadFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) parameters("Ljava/lang/String;", "Z", "Z", "I", "I") custom { _, classDef -> diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/user/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/user/Fingerprints.kt index 4bac74de7..94a9adb2b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/user/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/user/Fingerprints.kt @@ -9,28 +9,28 @@ internal fun userEndpointFingerprint(source: String, accessFlags: Set - fingerprint.stringMatches!!.first().index to fingerprint.method + fingerprint.stringMatches.first().index to fingerprint.method }.forEach { (userPathStringIndex, method) -> val userPathStringInstruction = method.getInstruction(userPathStringIndex) diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/video/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/video/Fingerprints.kt index 9ddeaf9cf..9da9830cf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/video/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/video/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.video import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode -internal val parseRedditVideoNetworkResponseFingerprint = fingerprint { +internal val parseRedditVideoNetworkResponseFingerprint by fingerprint { opcodes( Opcode.NEW_INSTANCE, Opcode.IGET_OBJECT, diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/video/FixVideoDownloadsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/video/FixVideoDownloadsPatch.kt index 64c33f308..cb4fa2465 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/video/FixVideoDownloadsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/video/FixVideoDownloadsPatch.kt @@ -24,9 +24,9 @@ val fixVideoDownloadsPatch = bytecodePatch( ) execute { - val scanResult = parseRedditVideoNetworkResponseFingerprint.patternMatch!! - val newInstanceIndex = scanResult.startIndex - val invokeDirectIndex = scanResult.endIndex - 1 + val scanResult = parseRedditVideoNetworkResponseFingerprint.instructionMatches + val newInstanceIndex = scanResult.first().index + val invokeDirectIndex = scanResult.last().index - 1 val buildResponseInstruction = parseRedditVideoNetworkResponseFingerprint.method.getInstruction(invokeDirectIndex) diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatch.kt deleted file mode 100644 index 28ad4a0db..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatch.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.revanced.patches.reddit.customclients.syncforreddit.fix.video - -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated( - message = "Patch was move to a different package", - ReplaceWith("app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.video.fixVideoDownloadsPatch") -) -@Suppress("unused") -val fixVideoDownloadsPatch = bytecodePatch { - dependsOn(app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.video.fixVideoDownloadsPatch) - - compatibleWith( - "com.laurencedawson.reddit_sync", - "com.laurencedawson.reddit_sync.pro", - "com.laurencedawson.reddit_sync.dev", - ) -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/layout/disablescreenshotpopup/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/layout/disablescreenshotpopup/Fingerprints.kt index 09fe16247..3127bbbc6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/layout/disablescreenshotpopup/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/layout/disablescreenshotpopup/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.reddit.layout.disablescreenshotpopup import app.revanced.patcher.fingerprint -internal val disableScreenshotPopupFingerprint = fingerprint { +internal val disableScreenshotPopupFingerprint by fingerprint { returns("V") parameters("Landroidx/compose/runtime/", "I") custom { method, classDef -> diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/Fingerprints.kt index 2eac1cbe2..803192a90 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.reddit.layout.premiumicon import app.revanced.patcher.fingerprint -internal val hasPremiumIconAccessFingerprint = fingerprint { +internal val hasPremiumIconAccessFingerprint by fingerprint { returns("Z") custom { method, classDef -> classDef.endsWith("MyAccount;") && method.name == "isPremiumSubscriber" diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/UnlockPremiumIconPatch.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/UnlockPremiumIconPatch.kt index 992ff27e5..5b8652a6f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/UnlockPremiumIconPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/UnlockPremiumIconPatch.kt @@ -20,9 +20,3 @@ val unlockPremiumIconsPatch = bytecodePatch( ) } } - -@Deprecated("Patch was renamed", ReplaceWith("unlockPremiumIconsPatch")) -@Suppress("unused") -val unlockPremiumIconPatch = bytecodePatch{ - dependsOn(unlockPremiumIconsPatch) -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/Fingerprints.kt index 3381fd2bb..b861b7940 100644 --- a/patches/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.reddit.misc.tracking.url import app.revanced.patcher.fingerprint -internal val shareLinkFormatterFingerprint = fingerprint { +internal val shareLinkFormatterFingerprint by fingerprint { custom { _, classDef -> classDef.startsWith("Lcom/reddit/sharing/") && classDef.sourceFile == "UrlUtil.kt" } diff --git a/patches/src/main/kotlin/app/revanced/patches/serviceportalbund/detection/root/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/serviceportalbund/detection/root/Fingerprints.kt index f7efe3103..f1b352b03 100644 --- a/patches/src/main/kotlin/app/revanced/patches/serviceportalbund/detection/root/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/serviceportalbund/detection/root/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.serviceportalbund.detection.root import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val rootDetectionFingerprint = fingerprint { +internal val rootDetectionFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("V") custom { _, classDef -> diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/Fingerprints.kt index df927dd4a..a83f3b1d2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/Fingerprints.kt @@ -1,11 +1,17 @@ package app.revanced.patches.shared import app.revanced.patcher.fingerprint +import app.revanced.patcher.string -internal val castContextFetchFingerprint = fingerprint { - strings("Error fetching CastContext.") +internal val castContextFetchFingerprint by fingerprint { + instructions( + string("Error fetching CastContext.") + ) } -internal val primeMethodFingerprint = fingerprint { - strings("com.google.android.GoogleCamera", "com.android.vending") +internal val primeMethodFingerprint by fingerprint { + instructions( + string("com.android.vending"), + string("com.google.android.GoogleCamera") + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/checks/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/checks/Fingerprints.kt index 0eabd2f54..b63e5c04a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/checks/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/checks/Fingerprints.kt @@ -2,10 +2,10 @@ package app.revanced.patches.shared.misc.checks import app.revanced.patcher.fingerprint -internal val patchInfoFingerprint = fingerprint { +internal val patchInfoFingerprint by fingerprint { custom { _, classDef -> classDef.type == "Lapp/revanced/extension/shared/checks/PatchInfo;" } } -internal val patchInfoBuildFingerprint = fingerprint { +internal val patchInfoBuildFingerprint by fingerprint { custom { _, classDef -> classDef.type == "Lapp/revanced/extension/shared/checks/PatchInfo\$Build;" } } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/Fingerprints.kt index 58cc5082f..b61a6763d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.shared.misc.extension import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val revancedUtilsPatchesVersionFingerprint = fingerprint { +internal val revancedUtilsPatchesVersionFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Ljava/lang/String;") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/SharedExtensionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/SharedExtensionPatch.kt index e6d78b777..f0be1f43b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/SharedExtensionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/extension/SharedExtensionPatch.kt @@ -2,10 +2,9 @@ package app.revanced.patches.shared.misc.extension import app.revanced.patcher.Fingerprint import app.revanced.patcher.FingerprintBuilder +import app.revanced.patcher.FingerprintDelegate import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.fingerprint import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch import app.revanced.util.returnEarly import com.android.tools.smali.dexlib2.iface.Method @@ -21,7 +20,7 @@ internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/shared/ */ fun sharedExtensionPatch( extensionName: String, - vararg hooks: ExtensionHook, + vararg hooks: () -> ExtensionHook, ) = bytecodePatch { dependsOn(sharedExtensionPatch(*hooks)) @@ -35,19 +34,18 @@ fun sharedExtensionPatch( * commonly for the onCreate method of exported activities. */ fun sharedExtensionPatch( - vararg hooks: ExtensionHook, + vararg hooks: () -> ExtensionHook, ) = bytecodePatch { extendWith("extensions/shared.rve") execute { - if (classes.none { EXTENSION_CLASS_DESCRIPTOR == it.type }) { - throw PatchException("Shared extension is not available. This patch can not succeed without it.") - } + // Verify the extension class exists. + classBy(EXTENSION_CLASS_DESCRIPTOR) } finalize { // The hooks are made in finalize to ensure that the context is hooked before any other patches. - hooks.forEach { hook -> hook(EXTENSION_CLASS_DESCRIPTOR) } + hooks.forEach { hook -> hook()(EXTENSION_CLASS_DESCRIPTOR) } // Modify Utils method to include the patches release version. revancedUtilsPatchesVersionFingerprint.method.apply { @@ -113,4 +111,7 @@ fun extensionHook( insertIndexResolver: BytecodePatchContext.(Method) -> Int = { 0 }, contextRegisterResolver: BytecodePatchContext.(Method) -> String = { "p0" }, fingerprintBuilderBlock: FingerprintBuilder.() -> Unit, -) = extensionHook(insertIndexResolver, contextRegisterResolver, fingerprint(block = fingerprintBuilderBlock)) +) = { + val fingerprint by FingerprintDelegate(block = fingerprintBuilderBlock) + ExtensionHook(fingerprint, insertIndexResolver, contextRegisterResolver) +} diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/Fingerprints.kt index 80d041ada..8b784b2db 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val canScrollVerticallyFingerprint = fingerprint { +internal val canScrollVerticallyFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch.kt index a01839c10..b4bc540a9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch.kt @@ -10,15 +10,17 @@ val verticalScrollPatch = bytecodePatch( ) { execute { - canScrollVerticallyFingerprint.method.apply { - val moveResultIndex = canScrollVerticallyFingerprint.patternMatch!!.endIndex - val moveResultRegister = getInstruction(moveResultIndex).registerA + canScrollVerticallyFingerprint.let { + it.method.apply { + val moveResultIndex = it.instructionMatches.last().index + val moveResultRegister = getInstruction(moveResultIndex).registerA - val insertIndex = moveResultIndex + 1 - addInstruction( - insertIndex, - "const/4 v$moveResultRegister, 0x0", - ) + val insertIndex = moveResultIndex + 1 + addInstruction( + insertIndex, + "const/4 v$moveResultRegister, 0x0", + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/Fingerprints.kt index b5f613d54..355a07ba8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/Fingerprints.kt @@ -3,15 +3,15 @@ package app.revanced.patches.shared.misc.gms import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -const val GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME = "getGmsCoreVendorGroupId" - -internal val gmsCoreSupportFingerprint = fingerprint { - custom { _, classDef -> - classDef.endsWith("GmsCoreSupport;") +internal val gmsCoreSupportFingerprint by fingerprint { + accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) + custom { method, classDef -> + method.name == "getGmsCoreVendorGroupId" + && classDef.endsWith("/GmsCoreSupport;") } } -internal val googlePlayUtilityFingerprint = fingerprint { +internal val googlePlayUtilityFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("I") parameters("L", "I") @@ -22,7 +22,7 @@ internal val googlePlayUtilityFingerprint = fingerprint { ) } -internal val serviceCheckFingerprint = fingerprint { +internal val serviceCheckFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("V") parameters("L", "I") diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/GmsCoreSupportPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/GmsCoreSupportPatch.kt index ef8743fda..4896e5163 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/GmsCoreSupportPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/gms/GmsCoreSupportPatch.kt @@ -78,7 +78,7 @@ fun gmsCoreSupportPatch( execute { fun transformStringReferences(transform: (str: String) -> String?) = classes.forEach { val mutableClass by lazy { - proxy(it).mutableClass + mutableClassBy(it) } it.methods.forEach classLoop@{ method -> @@ -88,12 +88,12 @@ fun gmsCoreSupportPatch( mutableClass.methods.first { MethodUtil.methodSignaturesMatch(it, method) } } - implementation.instructions.forEachIndexed insnLoop@{ index, instruction -> + implementation.instructions.forEachIndexed { index, instruction -> val string = ((instruction as? Instruction21c)?.reference as? StringReference)?.string - ?: return@insnLoop + ?: return@forEachIndexed // Apply transformation. - val transformedString = transform(string) ?: return@insnLoop + val transformedString = transform(string) ?: return@forEachIndexed mutableMethod.replaceInstruction( index, @@ -193,7 +193,15 @@ fun gmsCoreSupportPatch( primeMethodFingerprint?.let { transformPrimeMethod(packageName) } // Return these methods early to prevent the app from crashing. - earlyReturnFingerprints.forEach { it.method.returnEarly() } + earlyReturnFingerprints.forEach { + it.method.apply { + if (returnType == "Z") { + returnEarly(false) + } else { + returnEarly() + } + } + } serviceCheckFingerprint.method.returnEarly() // Google Play Utility is not present in all apps, so we need to check if it's present. @@ -211,9 +219,7 @@ fun gmsCoreSupportPatch( } // Change the vendor of GmsCore in the extension. - gmsCoreSupportFingerprint.classDef.methods - .single { it.name == GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME } - .replaceInstruction(0, "const-string v0, \"$gmsCoreVendorGroupId\"") + gmsCoreSupportFingerprint.method.replaceInstruction(0, "const-string v0, \"$gmsCoreVendorGroupId\"") executeBlock() } @@ -489,34 +495,6 @@ private object Constants { ) } -/** - * Abstract resource patch that allows Google apps to run without root and under a different package name - * by using GmsCore instead of Google Play Services. - * - * @param fromPackageName The package name of the original app. - * @param toPackageName The package name to fall back to if no custom package name is specified in patch options. - * @param spoofedPackageSignature The signature of the package to spoof to. - * @param gmsCoreVendorGroupIdOption The option to get the vendor group ID of GmsCore. - * @param executeBlock The additional execution block of the patch. - * @param block The additional block to build the patch. - */ -fun gmsCoreSupportResourcePatch( // This is here only for binary compatibility. - fromPackageName: String, - toPackageName: String, - spoofedPackageSignature: String, - gmsCoreVendorGroupIdOption: Option, - executeBlock: ResourcePatchContext.() -> Unit = {}, - block: ResourcePatchBuilder.() -> Unit = {}, -) = gmsCoreSupportResourcePatch( - fromPackageName, - toPackageName, - spoofedPackageSignature, - gmsCoreVendorGroupIdOption, - true, - executeBlock, - block -) - /** * Abstract resource patch that allows Google apps to run without root and under a different package name * by using GmsCore instead of Google Play Services. @@ -529,8 +507,7 @@ fun gmsCoreSupportResourcePatch( // This is here only for binary compatibility. * @param executeBlock The additional execution block of the patch. * @param block The additional block to build the patch. */ -// TODO: On the next major release make this public and delete the public overloaded constructor. -internal fun gmsCoreSupportResourcePatch( +fun gmsCoreSupportResourcePatch( fromPackageName: String, toPackageName: String, spoofedPackageSignature: String, diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt index 8a9e499dd..bb6aefcd0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt @@ -1,64 +1,107 @@ package app.revanced.patches.shared.misc.mapping +import app.revanced.patcher.InstructionFilter.Companion.METHOD_MAX_INSTRUCTIONS +import app.revanced.patcher.LiteralFilter +import app.revanced.patcher.literal import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.resourcePatch import org.w3c.dom.Element -import java.util.* -import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit +import java.util.Collections -// TODO: Probably renaming the patch/this is a good idea. -lateinit var resourceMappings: List - private set +enum class ResourceType(val value: String) { + ANIM("anim"), + ANIMATOR("animator"), + ARRAY("array"), + ATTR("attr"), + BOOL("bool"), + COLOR("color"), + DIMEN("dimen"), + DRAWABLE("drawable"), + FONT("font"), + FRACTION("fraction"), + ID("id"), + INTEGER("integer"), + INTERPOLATOR("interpolator"), + LAYOUT("layout"), + MENU("menu"), + MIPMAP("mipmap"), + NAVIGATION("navigation"), + PLURALS("plurals"), + RAW("raw"), + STRING("string"), + STYLE("style"), + STYLEABLE("styleable"), + TRANSITION("transition"), + VALUES("values"), + XML("xml"); -val resourceMappingPatch = resourcePatch { - val resourceMappings = Collections.synchronizedList(mutableListOf()) + companion object { + private val VALUE_MAP: Map = entries.associateBy { it.value } - execute { - val threadCount = Runtime.getRuntime().availableProcessors() - val threadPoolExecutor = Executors.newFixedThreadPool(threadCount) - - // Save the file in memory to concurrently read from it. - val resourceXmlFile = get("res/values/public.xml").readBytes() - - for (threadIndex in 0 until threadCount) { - threadPoolExecutor.execute thread@{ - document(resourceXmlFile.inputStream()).use { document -> - - val resources = document.documentElement.childNodes - val resourcesLength = resources.length - val jobSize = resourcesLength / threadCount - - val batchStart = jobSize * threadIndex - val batchEnd = jobSize * (threadIndex + 1) - element@ for (i in batchStart until batchEnd) { - // Prevent out of bounds. - if (i >= resourcesLength) return@thread - - val node = resources.item(i) - if (node !is Element) continue - - val nameAttribute = node.getAttribute("name") - val typeAttribute = node.getAttribute("type") - - if (node.nodeName != "public" || nameAttribute.startsWith("APKTOOL")) continue - - val id = node.getAttribute("id").substring(2).toLong(16) - - resourceMappings.add(ResourceElement(typeAttribute, nameAttribute, id)) - } - } - } - } - - threadPoolExecutor.also { it.shutdown() }.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS) - - app.revanced.patches.shared.misc.mapping.resourceMappings = resourceMappings + fun fromValue(value: String) = VALUE_MAP[value] + ?: throw IllegalArgumentException("Unknown resource type: $value") } } -operator fun List.get(type: String, name: String) = resourceMappings.firstOrNull { - it.type == type && it.name == name -}?.id ?: throw PatchException("Could not find resource type: $type name: $name") +data class ResourceElement(val type: ResourceType, val name: String, val id: Long) -data class ResourceElement internal constructor(val type: String, val name: String, val id: Long) +private lateinit var resourceMappings: MutableMap + +private fun setResourceId(type: ResourceType, name: String, id: Long) { + resourceMappings[type.value + name] = ResourceElement(type, name, id) +} + +/** + * @return A resource id of the given resource type and name. + * @throws PatchException if the resource is not found. + */ +fun getResourceId(type: ResourceType, name: String) = resourceMappings[type.value + name]?.id + ?: throw PatchException("Could not find resource type: $type name: $name") + +/** + * @return All resource elements. If a single resource id is needed instead use [getResourceId]. + */ +fun getResourceElements() = Collections.unmodifiableCollection(resourceMappings.values) + +/** + * @return If the resource exists. + */ +fun hasResourceId(type: ResourceType, name: String) = resourceMappings[type.value + name] != null + +/** + * Identical to [LiteralFilter] except uses a decoded resource literal value. + * + * Any patch with fingerprints of this filter must + * also declare [resourceMappingPatch] as a dependency. + */ +fun resourceLiteral( + type: ResourceType, + name: String, + maxBefore: Int = METHOD_MAX_INSTRUCTIONS, +) = literal({ getResourceId(type, name) }, null, maxBefore) + + +val resourceMappingPatch = resourcePatch { + execute { + // Use a stream of the file, since no modifications are done + // and using a File parameter causes the file to be re-wrote when closed. + document(get("res/values/public.xml").inputStream()).use { document -> + val resources = document.documentElement.childNodes + val resourcesLength = resources.length + resourceMappings = HashMap(2 * resourcesLength) + + for (i in 0 until resourcesLength) { + val node = resources.item(i) as? Element ?: continue + if (node.nodeName != "public") continue + + val nameAttribute = node.getAttribute("name") + if (nameAttribute.startsWith("APKTOOL")) continue + + val typeAttribute = node.getAttribute("type") + val id = node.getAttribute("id").substring(2).toLong(16) + + setResourceId(ResourceType.fromValue(typeAttribute), nameAttribute, id) + } + } + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/Fingerprints.kt index 344fd02da..509c99336 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/pairip/license/Fingerprints.kt @@ -2,14 +2,14 @@ package app.revanced.patches.shared.misc.pairip.license import app.revanced.patcher.fingerprint -internal val processLicenseResponseFingerprint = fingerprint { +internal val processLicenseResponseFingerprint by fingerprint { custom { method, classDef -> classDef.type == "Lcom/pairip/licensecheck/LicenseClient;" && method.name == "processResponse" } } -internal val validateLicenseResponseFingerprint = fingerprint { +internal val validateLicenseResponseFingerprint by fingerprint { custom { method, classDef -> classDef.type == "Lcom/pairip/licensecheck/ResponseValidator;" && method.name == "validateResponse" diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/Fingerprints.kt index cad00d8de..9d0fbb5d1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import app.revanced.patches.shared.misc.extension.EXTENSION_CLASS_DESCRIPTOR import com.android.tools.smali.dexlib2.AccessFlags -internal val themeLightColorResourceNameFingerprint = fingerprint { +internal val themeLightColorResourceNameFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returns("Ljava/lang/String;") parameters() @@ -13,7 +13,7 @@ internal val themeLightColorResourceNameFingerprint = fingerprint { } } -internal val themeDarkColorResourceNameFingerprint = fingerprint { +internal val themeDarkColorResourceNameFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returns("Ljava/lang/String;") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/SettingsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/SettingsPatch.kt index 828b20c12..8da55cfdb 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/SettingsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/SettingsPatch.kt @@ -7,7 +7,6 @@ import app.revanced.patches.all.misc.resources.addResource import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.settings.preference.BasePreference -import app.revanced.patches.shared.misc.settings.preference.IntentPreference import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference import app.revanced.util.ResourceGroup @@ -17,13 +16,6 @@ import app.revanced.util.insertFirst import app.revanced.util.returnEarly import org.w3c.dom.Node -// TODO: Delete this on next major version bump. -@Deprecated("Use non deprecated settings patch function") -fun settingsPatch ( - rootPreference: Pair, - preferences: Set, -) = settingsPatch(listOf(rootPreference), preferences) - private var themeForegroundColor : String? = null private var themeBackgroundColor : String? = null @@ -131,8 +123,7 @@ fun settingsPatch ( if (preference is PreferenceCategory) { removeIconsAndLayout(preference.preferences) - } - if (preference is PreferenceScreenPreference) { + } else if (preference is PreferenceScreenPreference) { removeIconsAndLayout(preference.preferences) } } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/ListPreference.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/ListPreference.kt index 2e26189b2..43de07ec2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/ListPreference.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/ListPreference.kt @@ -9,7 +9,6 @@ import org.w3c.dom.Document * * @param key The preference key. If null, other parameters must be specified. * @param titleKey The preference title key. - * @param summaryKey The preference summary key. * @param icon The preference icon resource name. * @param layout Layout declaration. * @param tag The preference class type. @@ -20,15 +19,12 @@ import org.w3c.dom.Document class ListPreference( key: String? = null, titleKey: String = "${key}_title", - /** Summary key is ignored and will be removed soon */ - //@Deprecated - summaryKey: String? = null, icon: String? = null, layout: String? = null, tag: String = "app.revanced.extension.shared.settings.preference.CustomDialogListPreference", val entriesKey: String? = "${key}_entries", val entryValuesKey: String? = "${key}_entry_values" -) : BasePreference(key, titleKey, summaryKey, icon, layout, tag) { +) : BasePreference(key, titleKey, null, icon, layout, tag) { var entries: ArrayResource? = null private set var entryValues: ArrayResource? = null diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt index e6169bacb..e7efdc41c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt @@ -1,11 +1,13 @@ package app.revanced.patches.shared.misc.spoof import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.string import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val buildInitPlaybackRequestFingerprint = fingerprint { +internal val buildInitPlaybackRequestFingerprint by fingerprint { returns("Lorg/chromium/net/UrlRequest\$Builder;") opcodes( Opcode.MOVE_RESULT_OBJECT, @@ -17,7 +19,7 @@ internal val buildInitPlaybackRequestFingerprint = fingerprint { ) } -internal val buildPlayerRequestURIFingerprint = fingerprint { +internal val buildPlayerRequestURIFingerprint by fingerprint { returns("Ljava/lang/String;") opcodes( Opcode.INVOKE_VIRTUAL, // Register holds player request URI. @@ -33,9 +35,12 @@ internal val buildPlayerRequestURIFingerprint = fingerprint { ) } -internal val buildRequestFingerprint = fingerprint { +internal val buildRequestFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) - returns("Lorg/chromium/net/UrlRequest;") + returns("Lorg/chromium/net/UrlRequest") // UrlRequest; or UrlRequest$Builder; + instructions( + methodCall(name = "newUrlRequestBuilder") + ) custom { methodDef, _ -> // Different targets have slightly different parameters @@ -58,13 +63,22 @@ internal val buildRequestFingerprint = fingerprint { // Lorg/chromium/net/UrlRequest\$Callback; // L + // 20.16+ uses a refactored and extracted method: + // L + // Ljava/util/Map; + // [B + // L + // Lorg/chromium/net/UrlRequest$Callback; + // L + val parameterTypes = methodDef.parameterTypes - (parameterTypes.size == 7 || parameterTypes.size == 8) && + val parameterTypesSize = parameterTypes.size + (parameterTypesSize == 6 || parameterTypesSize == 7 || parameterTypesSize == 8) && parameterTypes[1] == "Ljava/util/Map;" // URL headers. } } -internal val protobufClassParseByteBufferFingerprint = fingerprint { +internal val protobufClassParseByteBufferFingerprint by fingerprint { accessFlags(AccessFlags.PROTECTED, AccessFlags.STATIC) returns("L") parameters("L", "Ljava/nio/ByteBuffer;") @@ -77,9 +91,8 @@ internal val protobufClassParseByteBufferFingerprint = fingerprint { custom { method, _ -> method.name == "parseFrom" } } -internal val createStreamingDataFingerprint = fingerprint { +internal val createStreamingDataFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") parameters("L") opcodes( Opcode.IPUT_OBJECT, @@ -95,9 +108,8 @@ internal val createStreamingDataFingerprint = fingerprint { } } -internal val buildMediaDataSourceFingerprint = fingerprint { +internal val buildMediaDataSourceFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") parameters( "Landroid/net/Uri;", "J", @@ -112,29 +124,29 @@ internal val buildMediaDataSourceFingerprint = fingerprint { ) } -internal const val HLS_CURRENT_TIME_FEATURE_FLAG = 45355374L - -internal val hlsCurrentTimeFingerprint = fingerprint { +internal val hlsCurrentTimeFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters("Z", "L") - literal { - HLS_CURRENT_TIME_FEATURE_FLAG - } + instructions( + literal(45355374L) // HLS current time feature flag. + ) } -internal val nerdsStatsVideoFormatBuilderFingerprint = fingerprint { +internal val nerdsStatsVideoFormatBuilderFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Ljava/lang/String;") parameters("L") - strings("codecs=\"") + instructions( + string("codecs=\"") + ) } -internal val patchIncludedExtensionMethodFingerprint = fingerprint { +internal val patchIncludedExtensionMethodFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returns("Z") parameters() custom { method, classDef -> - classDef.type == EXTENSION_CLASS_DESCRIPTOR && method.name == "isPatchIncluded" + method.name == "isPatchIncluded" && classDef.type == EXTENSION_CLASS_DESCRIPTOR } } @@ -142,28 +154,28 @@ internal val patchIncludedExtensionMethodFingerprint = fingerprint { // This code appears to replace the player config after the streams are loaded. // Flag is present in YouTube 19.34, but is missing Platypus stream replacement code until 19.43. // Flag and Platypus code is also present in newer versions of YouTube Music. -internal const val MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG = 45645570L - -internal val mediaFetchHotConfigFingerprint = fingerprint { - literal { MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG } +internal val mediaFetchHotConfigFingerprint by fingerprint { + instructions( + literal(45645570L) + ) } // 20.10+ -internal const val MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG = 45683169L - -internal val mediaFetchHotConfigAlternativeFingerprint = fingerprint { - literal { MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG } +internal val mediaFetchHotConfigAlternativeFingerprint by fingerprint { + instructions( + literal(45683169L) + ) } // Feature flag that enables different code for parsing and starting video playback, // but it's exact purpose is not known. If this flag is enabled while stream spoofing // then videos will never start playback and load forever. // Flag does not seem to affect playback if spoofing is off. -internal const val PLAYBACK_START_CHECK_ENDPOINT_USED_FEATURE_FLAG = 45665455L - -internal val playbackStartDescriptorFeatureFlagFingerprint = fingerprint { +internal val playbackStartDescriptorFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters() returns("Z") - literal { PLAYBACK_START_CHECK_ENDPOINT_USED_FEATURE_FLAG } + instructions( + literal(45665455L) + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt index 78deda394..2789c105d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt @@ -23,7 +23,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.FieldReference -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 @@ -53,57 +52,59 @@ fun spoofVideoStreamsPatch( // region Block /initplayback requests to fall back to /get_watch requests. - val moveUriStringIndex = buildInitPlaybackRequestFingerprint.patternMatch!!.startIndex - buildInitPlaybackRequestFingerprint.method.apply { - val targetRegister = getInstruction(moveUriStringIndex).registerA + buildInitPlaybackRequestFingerprint.let { + it.method.apply { + val moveUriStringIndex = it.instructionMatches.first().index + val targetRegister = getInstruction(moveUriStringIndex).registerA - addInstructions( - moveUriStringIndex + 1, - """ - invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockInitPlaybackRequest(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$targetRegister - """, - ) + addInstructions( + moveUriStringIndex + 1, + """ + invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockInitPlaybackRequest(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$targetRegister + """ + ) + } } // endregion // region Block /get_watch requests to fall back to /player requests. - val invokeToStringIndex = buildPlayerRequestURIFingerprint.patternMatch!!.startIndex + buildPlayerRequestURIFingerprint.let { + it.method.apply { + val invokeToStringIndex = it.instructionMatches.first().index + val uriRegister = getInstruction(invokeToStringIndex).registerC - buildPlayerRequestURIFingerprint.method.apply { - val uriRegister = getInstruction(invokeToStringIndex).registerC - - addInstructions( - invokeToStringIndex, - """ - invoke-static { v$uriRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockGetWatchRequest(Landroid/net/Uri;)Landroid/net/Uri; - move-result-object v$uriRegister - """, - ) + addInstructions( + invokeToStringIndex, + """ + invoke-static { v$uriRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockGetWatchRequest(Landroid/net/Uri;)Landroid/net/Uri; + move-result-object v$uriRegister + """ + ) + } } // endregion // region Get replacement streams at player requests. - buildRequestFingerprint.method.apply { - val newRequestBuilderIndex = indexOfFirstInstructionOrThrow { - opcode == Opcode.INVOKE_VIRTUAL && - getReference()?.name == "newUrlRequestBuilder" - } - val urlRegister = getInstruction(newRequestBuilderIndex).registerD - val freeRegister = findFreeRegister(newRequestBuilderIndex, urlRegister) + buildRequestFingerprint.let { + it.method.apply { + val builderIndex = it.instructionMatches.first().index + val urlRegister = getInstruction(builderIndex).registerD + val freeRegister = findFreeRegister(builderIndex, urlRegister) - addInstructions( - newRequestBuilderIndex, - """ - move-object v$freeRegister, p1 - invoke-static { v$urlRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V - """ - ) + addInstructions( + builderIndex, + """ + move-object v$freeRegister, p1 + invoke-static { v$urlRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V + """ + ) + } } // endregion @@ -113,7 +114,7 @@ fun spoofVideoStreamsPatch( createStreamingDataFingerprint.method.apply { val setStreamDataMethodName = "patch_setStreamingData" val resultMethodType = createStreamingDataFingerprint.classDef.type - val videoDetailsIndex = createStreamingDataFingerprint.patternMatch!!.endIndex + val videoDetailsIndex = createStreamingDataFingerprint.instructionMatches.last().index val videoDetailsRegister = getInstruction(videoDetailsIndex).registerA val videoDetailsClass = getInstruction(videoDetailsIndex).getReference()!!.type @@ -124,7 +125,7 @@ fun spoofVideoStreamsPatch( ) val protobufClass = protobufClassParseByteBufferFingerprint.method.definingClass - val setStreamingDataIndex = createStreamingDataFingerprint.patternMatch!!.startIndex + val setStreamingDataIndex = createStreamingDataFingerprint.instructionMatches.first().index val playerProtoClass = getInstruction(setStreamingDataIndex + 1) .getReference()!!.definingClass @@ -235,34 +236,42 @@ fun spoofVideoStreamsPatch( // region Fix iOS livestream current time. - hlsCurrentTimeFingerprint.method.insertLiteralOverride( - HLS_CURRENT_TIME_FEATURE_FLAG, - "$EXTENSION_CLASS_DESCRIPTOR->fixHLSCurrentTime(Z)Z" - ) + hlsCurrentTimeFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->fixHLSCurrentTime(Z)Z" + ) + } // endregion // region turn off stream config replacement feature flag. if (fixMediaFetchHotConfigChanges()) { - mediaFetchHotConfigFingerprint.method.insertLiteralOverride( - MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG, - "$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z" - ) + mediaFetchHotConfigFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z" + ) + } } if (fixMediaFetchHotConfigAlternativeChanges()) { - mediaFetchHotConfigAlternativeFingerprint.method.insertLiteralOverride( - MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG, - "$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z" - ) + mediaFetchHotConfigAlternativeFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z" + ) + } } if (fixParsePlaybackResponseFeatureFlag()) { - playbackStartDescriptorFeatureFlagFingerprint.method.insertLiteralOverride( - PLAYBACK_START_CHECK_ENDPOINT_USED_FEATURE_FLAG, - "$EXTENSION_CLASS_DESCRIPTOR->usePlaybackStartFeatureFlag(Z)Z" - ) + playbackStartDescriptorFeatureFlagFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->usePlaybackStartFeatureFlag(Z)Z" + ) + } } // endregion diff --git a/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/Fingerprints.kt index 0e81d7e59..3b0363443 100644 --- a/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.solidexplorer2.functionality.filesize import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode -internal val onReadyFingerprint = fingerprint { +internal val onReadyFingerprint by fingerprint { opcodes( Opcode.CONST_WIDE_32, // Constant storing the 2MB limit Opcode.CMP_LONG, diff --git a/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/RemoveFileSizeLimitPatch.kt b/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/RemoveFileSizeLimitPatch.kt index 7ef509301..c75a12b11 100644 --- a/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/RemoveFileSizeLimitPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/solidexplorer2/functionality/filesize/RemoveFileSizeLimitPatch.kt @@ -14,7 +14,7 @@ val removeFileSizeLimitPatch = bytecodePatch( execute { onReadyFingerprint.method.apply { - val cmpIndex = onReadyFingerprint.patternMatch!!.startIndex + 1 + val cmpIndex = onReadyFingerprint.instructionMatches.first().index + 1 val cmpResultRegister = getInstruction(cmpIndex).registerA replaceInstruction(cmpIndex, "const/4 v$cmpResultRegister, 0x0") diff --git a/patches/src/main/kotlin/app/revanced/patches/songpal/badge/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/songpal/badge/Fingerprints.kt index c52174f2c..48ef210a7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/songpal/badge/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/songpal/badge/Fingerprints.kt @@ -8,7 +8,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference // Located @ ub.i0.h#p (9.5.0) -internal val createTabsFingerprint = fingerprint { +internal val createTabsFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE) returns("Ljava/util/List;") custom { method, _ -> @@ -26,7 +26,7 @@ internal val createTabsFingerprint = fingerprint { } // Located @ com.sony.songpal.mdr.vim.activity.MdrRemoteBaseActivity.e#run (9.5.0) -internal val showNotificationFingerprint = fingerprint { +internal val showNotificationFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("V") custom { method, _ -> diff --git a/patches/src/main/kotlin/app/revanced/patches/soundcloud/ad/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/soundcloud/ad/Fingerprints.kt index 28780ea57..f6f442306 100644 --- a/patches/src/main/kotlin/app/revanced/patches/soundcloud/ad/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/soundcloud/ad/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val interceptFingerprint = fingerprint { +internal val interceptFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("L") parameters("L") @@ -16,9 +16,8 @@ internal val interceptFingerprint = fingerprint { strings("SC-Mob-UserPlan", "Configuration") } -internal val userConsumerPlanConstructorFingerprint = fingerprint { +internal val userConsumerPlanConstructorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") parameters( "Ljava/lang/String;", "Z", diff --git a/patches/src/main/kotlin/app/revanced/patches/soundcloud/ad/HideAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/soundcloud/ad/HideAdsPatch.kt index 47a54ed60..2d4abc0f2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/soundcloud/ad/HideAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/soundcloud/ad/HideAdsPatch.kt @@ -54,7 +54,7 @@ val hideAdsPatch = bytecodePatch( // Prevent verification of an HTTP header containing the user's current plan, which would contradict the previous patch. - val conditionIndex = interceptFingerprint.patternMatch!!.endIndex + 1 + val conditionIndex = interceptFingerprint.instructionMatches.last().index + 1 interceptFingerprint.method.addInstruction( conditionIndex, "return-object p1", diff --git a/patches/src/main/kotlin/app/revanced/patches/soundcloud/analytics/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/soundcloud/analytics/Fingerprints.kt index 2954b4d99..1b18832b7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/soundcloud/analytics/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/soundcloud/analytics/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.soundcloud.analytics import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val createTrackingApiFingerprint = fingerprint { +internal val createTrackingApiFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("L") custom { methodDef, _ -> diff --git a/patches/src/main/kotlin/app/revanced/patches/soundcloud/offlinesync/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/soundcloud/offlinesync/Fingerprints.kt index 688fe3604..fe2aab19a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/soundcloud/offlinesync/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/soundcloud/offlinesync/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val downloadOperationsURLBuilderFingerprint = fingerprint { +internal val downloadOperationsURLBuilderFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/String") parameters("L", "L") @@ -15,7 +15,7 @@ internal val downloadOperationsURLBuilderFingerprint = fingerprint { ) } -internal val downloadOperationsHeaderVerificationFingerprint = fingerprint { +internal val downloadOperationsHeaderVerificationFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L", "L") diff --git a/patches/src/main/kotlin/app/revanced/patches/soundcloud/shared/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/soundcloud/shared/Fingerprints.kt index 3a50ae407..646bb929a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/soundcloud/shared/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/soundcloud/shared/Fingerprints.kt @@ -4,8 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val featureConstructorFingerprint = fingerprint { - returns("V") +internal val featureConstructorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameters("Ljava/lang/String;", "Z", "Ljava/util/List;") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/hide/createbutton/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/hide/createbutton/Fingerprints.kt index 5d555b187..5b157f924 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/hide/createbutton/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/hide/createbutton/Fingerprints.kt @@ -7,11 +7,11 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal val navigationBarItemSetClassFingerprint = fingerprint { +internal val navigationBarItemSetClassFingerprint by fingerprint { strings("NavigationBarItemSet(") } -internal val navigationBarItemSetConstructorFingerprint = fingerprint { +internal val navigationBarItemSetConstructorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) // Make sure the method checks whether navigation bar items are null before adding them. // If this is not true, then we cannot patch the method and potentially transform the parameters into null. @@ -23,6 +23,6 @@ internal val navigationBarItemSetConstructorFingerprint = fingerprint { } } -internal val oldNavigationBarAddItemFingerprint = fingerprint { +internal val oldNavigationBarAddItemFingerprint by fingerprint { strings("Bottom navigation tabs exceeds maximum of 5 tabs") } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt index eb3ab7839..5de56ca82 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/Fingerprints.kt @@ -4,21 +4,21 @@ import app.revanced.patcher.fingerprint import app.revanced.util.containsLiteralInstruction import com.android.tools.smali.dexlib2.AccessFlags -internal val colorSpaceUtilsClassFingerprint = fingerprint { +internal val colorSpaceUtilsClassFingerprint by fingerprint { strings("The specified color must be encoded in an RGB color space.") // Partial string match. } -internal val convertArgbToRgbaFingerprint = fingerprint { +internal val convertArgbToRgbaFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC, AccessFlags.FINAL) returns("J") parameters("J") } -internal val parseLottieJsonFingerprint = fingerprint { +internal val parseLottieJsonFingerprint by fingerprint { strings("Unsupported matte type: ") } -internal val parseAnimatedColorFingerprint = fingerprint { +internal val parseAnimatedColorFingerprint by fingerprint { parameters("L", "F") returns("Ljava/lang/Object;") custom { method, _ -> diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/lite/ondemand/OnDemandPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/lite/ondemand/OnDemandPatch.kt deleted file mode 100644 index 4d2d04a55..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/lite/ondemand/OnDemandPatch.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.spotify.lite.ondemand - -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated("Patch no longer works and will be deleted soon") -@Suppress("unused") -val onDemandPatch = bytecodePatch( - description = "Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads.", -) diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/ExtensionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/ExtensionPatch.kt index 070190a03..2736a0e37 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/ExtensionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/ExtensionPatch.kt @@ -3,7 +3,7 @@ package app.revanced.patches.spotify.misc.extension import app.revanced.patches.shared.misc.extension.sharedExtensionPatch val sharedExtensionPatch = sharedExtensionPatch( - "spotify", + "spotify", mainActivityOnCreateHook, loadOrbitLibraryHook ) diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Fingerprints.kt index 13b6094d3..7133e16de 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Fingerprints.kt @@ -2,6 +2,6 @@ package app.revanced.patches.spotify.misc.extension import app.revanced.patcher.fingerprint -internal val loadOrbitLibraryFingerprint = fingerprint { +internal val loadOrbitLibraryFingerprint by fingerprint { strings("OrbitLibraryLoader", "cst") } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt index 4bddc43b8..9eca1b7d1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/extension/Hooks.kt @@ -8,19 +8,23 @@ import app.revanced.util.indexOfFirstInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.FieldReference -internal val mainActivityOnCreateHook = extensionHook(fingerprint = mainActivityOnCreateFingerprint) +internal val mainActivityOnCreateHook = extensionHook { mainActivityOnCreateFingerprint } -internal val loadOrbitLibraryHook = extensionHook( - insertIndexResolver = { - loadOrbitLibraryFingerprint.stringMatches!!.last().index - }, - contextRegisterResolver = { method -> - val contextReferenceIndex = method.indexOfFirstInstruction { - getReference()?.type == "Landroid/content/Context;" - } - val contextRegister = method.getInstruction(contextReferenceIndex).registerA +internal val loadOrbitLibraryHook = extensionHook { + // FIXME: Creating this is a mess and needs refactoring. + extensionHook( + insertIndexResolver = { + loadOrbitLibraryFingerprint.stringMatches.last().index + }, + contextRegisterResolver = { method -> + val contextReferenceIndex = method.indexOfFirstInstruction { + getReference()?.type == "Landroid/content/Context;" + } + val contextRegister = + method.getInstruction(contextReferenceIndex).registerA - "v$contextRegister" - }, - fingerprint = loadOrbitLibraryFingerprint, -) + "v$contextRegister" + }, + fingerprint = loadOrbitLibraryFingerprint, + ) +} diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/Fingerprints.kt index 3be19dcce..177157ab1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/Fingerprints.kt @@ -1,17 +1,18 @@ package app.revanced.patches.spotify.misc.fix import app.revanced.patcher.fingerprint +import app.revanced.patcher.string import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal val loadOrbitLibraryFingerprint = fingerprint { +internal val loadOrbitLibraryFingerprint by fingerprint { strings("/liborbit-jni-spotify.so") } -internal val setClientIdFingerprint = fingerprint { +internal val setClientIdFingerprint by fingerprint { parameters("Ljava/lang/String;") custom { method, classDef -> classDef.type == "Lcom/spotify/connectivity/ApplicationScopeConfiguration;" @@ -19,7 +20,7 @@ internal val setClientIdFingerprint = fingerprint { } } -internal val setUserAgentFingerprint = fingerprint { +internal val setUserAgentFingerprint by fingerprint { parameters("Ljava/lang/String;") custom { method, classDef -> classDef.type == "Lcom/spotify/connectivity/ApplicationScopeConfiguration;" @@ -27,11 +28,11 @@ internal val setUserAgentFingerprint = fingerprint { } } -internal val extensionFixConstantsFingerprint = fingerprint { +internal val extensionFixConstantsFingerprint by fingerprint { custom { _, classDef -> classDef.type == "Lapp/revanced/extension/spotify/misc/fix/Constants;" } } -internal val runIntegrityVerificationFingerprint = fingerprint { +internal val runIntegrityVerificationFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofPackageInfoPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofPackageInfoPatch.kt deleted file mode 100644 index 20f9b3b4e..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofPackageInfoPatch.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.spotify.misc.fix - -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated("Superseded by spoofClientPatch", ReplaceWith("spoofClientPatch")) -@Suppress("unused") -val spoofPackageInfoPatch = bytecodePatch( - description = "Spoofs the package info of the app to fix various functions of the app.", -) { - dependsOn(spoofClientPatch) -} diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofSignaturePatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofSignaturePatch.kt deleted file mode 100644 index 238da0f41..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/SpoofSignaturePatch.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.spotify.misc.fix - -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated("Superseded by spoofClientPatch", ReplaceWith("spoofClientPatch")) -@Suppress("unused") -val spoofSignaturePatch = bytecodePatch( - description = "Spoofs the signature of the app fix various functions of the app.", -) { - dependsOn(spoofClientPatch) -} diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/Fingerprints.kt index b9edaaeac..8548ece44 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/fix/login/Fingerprints.kt @@ -1,13 +1,14 @@ package app.revanced.patches.spotify.misc.fix.login import app.revanced.patcher.fingerprint +import app.revanced.patcher.literal import app.revanced.util.literal -internal val katanaProxyLoginMethodHandlerClassFingerprint = fingerprint { +internal val katanaProxyLoginMethodHandlerClassFingerprint by fingerprint { strings("katana_proxy_auth") } -internal val katanaProxyLoginMethodTryAuthorizeFingerprint = fingerprint { +internal val katanaProxyLoginMethodTryAuthorizeFingerprint by fingerprint { strings("e2e") literal { 0 } } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/ChangeLyricsProviderPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/ChangeLyricsProviderPatch.kt index 6adaec7c7..2df7c6b1a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/ChangeLyricsProviderPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/ChangeLyricsProviderPatch.kt @@ -3,10 +3,12 @@ package app.revanced.patches.spotify.misc.lyrics import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.fingerprint import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.stringOption import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c @@ -87,7 +89,18 @@ val changeLyricsProviderPatch = bytecodePatch( // region Replace the call to the HTTP client builder method used exclusively for lyrics by the modified one. - getLyricsHttpClientFingerprint(httpClientBuilderMethod).method.apply { + + val getLyricsHttpClientFingerprint by fingerprint { + returns(httpClientBuilderMethod.returnType) + parameters() + custom { method, _ -> + method.indexOfFirstInstruction { + getReference() == httpClientBuilderMethod + } >= 0 + } + } + + getLyricsHttpClientFingerprint.method.apply { val getLyricsHttpClientIndex = indexOfFirstInstructionOrThrow { getReference() == httpClientBuilderMethod } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/Fingerprints.kt index f55fc349f..b0ca65416 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/lyrics/Fingerprints.kt @@ -5,7 +5,7 @@ import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal val httpClientBuilderFingerprint = fingerprint { +internal val httpClientBuilderFingerprint by fingerprint { strings("client == null", "scheduler == null") } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/privacy/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/privacy/Fingerprints.kt index a84aa699b..e6fabc4c9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/privacy/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/privacy/Fingerprints.kt @@ -5,7 +5,7 @@ import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val shareCopyUrlFingerprint = fingerprint { +internal val shareCopyUrlFingerprint by fingerprint { returns("Ljava/lang/Object;") parameters("Ljava/lang/Object;") strings("clipboard", "Spotify Link") @@ -14,7 +14,7 @@ internal val shareCopyUrlFingerprint = fingerprint { } } -internal val oldShareCopyUrlFingerprint = fingerprint { +internal val oldShareCopyUrlFingerprint by fingerprint { returns("Ljava/lang/Object;") parameters("Ljava/lang/Object;") strings("clipboard", "createNewSession failed") @@ -23,7 +23,7 @@ internal val oldShareCopyUrlFingerprint = fingerprint { } } -internal val formatAndroidShareSheetUrlFingerprint = fingerprint { +internal val formatAndroidShareSheetUrlFingerprint by fingerprint { returns("Ljava/lang/String;") parameters("L", "Ljava/lang/String;") opcodes( @@ -38,7 +38,7 @@ internal val formatAndroidShareSheetUrlFingerprint = fingerprint { } } -internal val oldFormatAndroidShareSheetUrlFingerprint = fingerprint { +internal val oldFormatAndroidShareSheetUrlFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("Ljava/lang/String;") parameters("Lcom/spotify/share/social/sharedata/ShareData;", "Ljava/lang/String;") diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/widgets/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/widgets/Fingerprints.kt index 3566512e8..81bcb2412 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/widgets/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/widgets/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.spotify.misc.widgets import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode -internal val canBindAppWidgetPermissionFingerprint = fingerprint { +internal val canBindAppWidgetPermissionFingerprint by fingerprint { strings("android.permission.BIND_APPWIDGET") opcodes(Opcode.AND_INT_LIT8) } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/navbar/PremiumNavbarTabPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/navbar/PremiumNavbarTabPatch.kt deleted file mode 100644 index bcf94324c..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/navbar/PremiumNavbarTabPatch.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.spotify.navbar - -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated("Obsolete and will be deleted soon") -@Suppress("unused") -val premiumNavbarTabPatch = bytecodePatch( - description = "Hides the premium tab from the navigation bar.", -) diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/shared/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/shared/Fingerprints.kt index 103f47750..658b3a9ef 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/shared/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/shared/Fingerprints.kt @@ -5,7 +5,7 @@ import com.android.tools.smali.dexlib2.AccessFlags private const val SPOTIFY_MAIN_ACTIVITY = "Lcom/spotify/music/SpotifyMainActivity;" -internal val mainActivityOnCreateFingerprint = fingerprint { +internal val mainActivityOnCreateFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Landroid/os/Bundle;") diff --git a/patches/src/main/kotlin/app/revanced/patches/strava/subscription/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/strava/subscription/Fingerprints.kt index 0458f45d3..58047cc4c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/strava/subscription/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/strava/subscription/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.strava.subscription import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode -internal val getSubscribedFingerprint = fingerprint { +internal val getSubscribedFingerprint by fingerprint { opcodes(Opcode.IGET_BOOLEAN) custom { method, classDef -> classDef.endsWith("/SubscriptionDetailResponse;") && method.name == "getSubscribed" diff --git a/patches/src/main/kotlin/app/revanced/patches/strava/subscription/UnlockSubscriptionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/strava/subscription/UnlockSubscriptionPatch.kt index e59660472..d0e061b9c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/strava/subscription/UnlockSubscriptionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/strava/subscription/UnlockSubscriptionPatch.kt @@ -12,7 +12,7 @@ val unlockSubscriptionPatch = bytecodePatch( execute { getSubscribedFingerprint.method.replaceInstruction( - getSubscribedFingerprint.patternMatch!!.startIndex, + getSubscribedFingerprint.instructionMatches.first().index, "const/4 v0, 0x1", ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/strava/upselling/DisableSubscriptionSuggestionsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/strava/upselling/DisableSubscriptionSuggestionsPatch.kt index c91bb961a..69fcc44d4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/strava/upselling/DisableSubscriptionSuggestionsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/strava/upselling/DisableSubscriptionSuggestionsPatch.kt @@ -52,7 +52,7 @@ val disableSubscriptionSuggestionsPatch = bytecodePatch( }, ) - val getModulesIndex = getModulesFingerprint.patternMatch!!.startIndex + val getModulesIndex = getModulesFingerprint.instructionMatches.first().index with(originalMethod) { removeInstruction(getModulesIndex) addInstructions( diff --git a/patches/src/main/kotlin/app/revanced/patches/strava/upselling/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/strava/upselling/Fingerprints.kt index 1204a36f2..134c10869 100644 --- a/patches/src/main/kotlin/app/revanced/patches/strava/upselling/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/strava/upselling/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.strava.upselling import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode -internal val getModulesFingerprint = fingerprint { +internal val getModulesFingerprint by fingerprint { opcodes(Opcode.IGET_OBJECT) custom { method, classDef -> classDef.endsWith("/GenericLayoutEntry;") && method.name == "getModules" diff --git a/patches/src/main/kotlin/app/revanced/patches/swissid/integritycheck/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/swissid/integritycheck/Fingerprints.kt index 0efa845fb..6e55bd5f4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/swissid/integritycheck/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/swissid/integritycheck/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.swissid.integritycheck import app.revanced.patcher.fingerprint -internal val checkIntegrityFingerprint = fingerprint { +internal val checkIntegrityFingerprint by fingerprint { returns("V") parameters("Lcom/swisssign/deviceintegrity/model/DeviceIntegrityResult;") strings("it", "result") diff --git a/patches/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/Fingerprints.kt index 4bd688de4..e198d21b1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/Fingerprints.kt @@ -2,13 +2,13 @@ package app.revanced.patches.ticktick.misc.themeunlock import app.revanced.patcher.fingerprint -internal val checkLockedThemesFingerprint = fingerprint { +internal val checkLockedThemesFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("Theme;") && method.name == "isLockedTheme" } } -internal val setThemeFingerprint = fingerprint { +internal val setThemeFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("ThemePreviewActivity;") && method.name == "lambda\$updateUserBtn\$1" } diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/Fingerprints.kt index f85dd2d07..32cf50f13 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/Fingerprints.kt @@ -4,13 +4,13 @@ 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 by fingerprint { custom { method, classDef -> classDef.endsWith("/FeedApiService;") && method.name == "fetchFeedList" } } -internal val followFeedFingerprint = fingerprint { +internal val followFeedFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;") strings("getFollowFeedList") diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/Fingerprints.kt index eb2868374..43aab883c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.tiktok.interaction.cleardisplay import app.revanced.patcher.fingerprint -internal val onClearDisplayEventFingerprint = fingerprint { +internal val onClearDisplayEventFingerprint by fingerprint { custom { method, classDef -> // Internally the feature is called "Clear mode". classDef.endsWith("/ClearModePanelComponent;") && method.name == "onClearModeEvent" diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/Fingerprints.kt index 160b49c15..5ab0efbbb 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.tiktok.interaction.downloads import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val aclCommonShareFingerprint = fingerprint { +internal val aclCommonShareFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("I") custom { method, classDef -> @@ -12,7 +12,7 @@ internal val aclCommonShareFingerprint = fingerprint { } } -internal val aclCommonShare2Fingerprint = fingerprint { +internal val aclCommonShare2Fingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("I") custom { method, classDef -> @@ -21,7 +21,7 @@ internal val aclCommonShare2Fingerprint = fingerprint { } } -internal val aclCommonShare3Fingerprint = fingerprint { +internal val aclCommonShare3Fingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("I") custom { method, classDef -> @@ -30,7 +30,7 @@ internal val aclCommonShare3Fingerprint = fingerprint { } } -internal val downloadUriFingerprint = fingerprint { +internal val downloadUriFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Landroid/net/Uri;") parameters( diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/Fingerprints.kt index ce372ea42..66fef7177 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/Fingerprints.kt @@ -2,10 +2,10 @@ package app.revanced.patches.tiktok.interaction.seekbar import app.revanced.patcher.fingerprint -internal val setSeekBarShowTypeFingerprint = fingerprint { +internal val setSeekBarShowTypeFingerprint by fingerprint { strings("seekbar show type change, change to:") } -internal val shouldShowSeekBarFingerprint = fingerprint { +internal val shouldShowSeekBarFingerprint by fingerprint { strings("can not show seekbar, state: 1, not in resume") } diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/Fingerprints.kt index 221036bb9..ab224a1cc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/Fingerprints.kt @@ -3,13 +3,13 @@ package app.revanced.patches.tiktok.interaction.speed import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val getSpeedFingerprint = fingerprint { +internal val getSpeedFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("/BaseListFragmentPanel;") && method.name == "onFeedSpeedSelectedEvent" } } -internal val setSpeedFingerprint = fingerprint { +internal val setSpeedFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("V") parameters("Ljava/lang/String;", "Lcom/ss/android/ugc/aweme/feed/model/Aweme;", "F") diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/Fingerprints.kt index 929ef8672..439f63862 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/Fingerprints.kt @@ -2,14 +2,14 @@ package app.revanced.patches.tiktok.misc.login.disablerequirement import app.revanced.patcher.fingerprint -internal val mandatoryLoginServiceFingerprint = fingerprint { +internal val mandatoryLoginServiceFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("/MandatoryLoginService;") && method.name == "enableForcedLogin" } } -internal val mandatoryLoginService2Fingerprint = fingerprint { +internal val mandatoryLoginService2Fingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("/MandatoryLoginService;") && method.name == "shouldShowForcedLogin" diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/Fingerprints.kt index a40f5251f..19d045db0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.tiktok.misc.login.fixgoogle import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val googleAuthAvailableFingerprint = fingerprint { +internal val googleAuthAvailableFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() @@ -12,7 +12,7 @@ internal val googleAuthAvailableFingerprint = fingerprint { } } -internal val googleOneTapAuthAvailableFingerprint = fingerprint { +internal val googleOneTapAuthAvailableFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/Fingerprints.kt index d1c4d6de6..4317948c4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/Fingerprints.kt @@ -2,32 +2,32 @@ package app.revanced.patches.tiktok.misc.settings import app.revanced.patcher.fingerprint -internal val addSettingsEntryFingerprint = fingerprint { +internal val addSettingsEntryFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("/SettingNewVersionFragment;") && method.name == "initUnitManger" } } -internal val adPersonalizationActivityOnCreateFingerprint = fingerprint { +internal val adPersonalizationActivityOnCreateFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("/AdPersonalizationActivity;") && method.name == "onCreate" } } -internal val settingsEntryFingerprint = fingerprint { +internal val settingsEntryFingerprint by fingerprint { strings("pls pass item or extends the EventUnit") } -internal val settingsEntryInfoFingerprint = fingerprint { +internal val settingsEntryInfoFingerprint by fingerprint { strings( "ExposeItem(title=", ", icon=", ) } -internal val settingsStatusLoadFingerprint = fingerprint { +internal val settingsStatusLoadFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("Lapp/revanced/extension/tiktok/settings/SettingsStatus;") && method.name == "load" diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt index 40a45650d..b069b88f5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt @@ -69,7 +69,7 @@ val spoofSimPatch = bytecodePatch( } } }.forEach { (classDef, methods) -> - with(proxy(classDef).mutableClass) { + with(mutableClassBy(classDef)) { methods.forEach { (method, patches) -> with(findMutableMethodOf(method)) { while (!patches.isEmpty()) { diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/shared/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/shared/Fingerprints.kt index 3e98d213e..508d46964 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/shared/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/shared/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val getEnterFromFingerprint = fingerprint { +internal val getEnterFromFingerprint by fingerprint { returns("Ljava/lang/String;") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters("Z") @@ -22,7 +22,7 @@ internal val getEnterFromFingerprint = fingerprint { } } -internal val onRenderFirstFrameFingerprint = fingerprint { +internal val onRenderFirstFrameFingerprint by fingerprint { strings("method_enable_viewpager_preload_duration") custom { _, classDef -> classDef.endsWith("/BaseListFragmentPanel;") diff --git a/patches/src/main/kotlin/app/revanced/patches/trakt/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/trakt/Fingerprints.kt index 4a02c6221..0d985d88c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/trakt/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/trakt/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.trakt import app.revanced.patcher.fingerprint -internal val isVIPEPFingerprint = fingerprint { +internal val isVIPEPFingerprint by fingerprint { custom { method, classDef -> if (!classDef.endsWith("RemoteUser;")) return@custom false @@ -10,7 +10,7 @@ internal val isVIPEPFingerprint = fingerprint { } } -internal val isVIPFingerprint = fingerprint { +internal val isVIPFingerprint by fingerprint { custom { method, classDef -> if (!classDef.endsWith("RemoteUser;")) return@custom false @@ -18,7 +18,7 @@ internal val isVIPFingerprint = fingerprint { } } -internal val remoteUserFingerprint = fingerprint { +internal val remoteUserFingerprint by fingerprint { custom { _, classDef -> classDef.endsWith("RemoteUser;") } diff --git a/patches/src/main/kotlin/app/revanced/patches/tudortmund/lockscreen/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tudortmund/lockscreen/Fingerprints.kt index 12ffa15c1..0cd634ee1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tudortmund/lockscreen/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tudortmund/lockscreen/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.tudortmund.lockscreen import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val brightnessFingerprint = fingerprint { +internal val brightnessFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("V") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/annoyances/notifications/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/annoyances/notifications/Fingerprints.kt index 67e051a7b..525f5a5e7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/annoyances/notifications/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/annoyances/notifications/Fingerprints.kt @@ -6,6 +6,6 @@ import app.revanced.patcher.fingerprint // It shows whenever you visit a certain blog for the second time and disables itself // if it was shown a total of 3 times (stored in app storage). // This targets the BlogNotifyCtaDialog.isEnabled() method to let it always return false. -internal val isBlogNotifyEnabledFingerprint = fingerprint { +internal val isBlogNotifyEnabledFingerprint by fingerprint { strings("isEnabled --> ", "blog_notify_enabled") } diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/annoyances/popups/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/annoyances/popups/Fingerprints.kt index 7d00f2f1b..2be1a3cef 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/annoyances/popups/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/annoyances/popups/Fingerprints.kt @@ -4,7 +4,7 @@ import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint // This method is responsible for loading and displaying the visual Layout of the Gift Message Popup. -internal val showGiftMessagePopupFingerprint = fingerprint { +internal val showGiftMessagePopupFingerprint by fingerprint { accessFlags(AccessFlags.FINAL, AccessFlags.PUBLIC) returns("V") strings("activity", "anchorView", "textMessage") diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/Fingerprints.kt index e24ca2884..742a8fd4d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/Fingerprints.kt @@ -13,7 +13,7 @@ import app.revanced.patcher.fingerprint // Some features seem to be very old and never removed, though, such as Google Login. // The startIndex of the opcode pattern is at the start of the function after the arg null check. // we want to insert our instructions there. -internal val getFeatureValueFingerprint = fingerprint { +internal val getFeatureValueFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/String;") parameters("L", "Z") diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/OverrideFeatureFlagsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/OverrideFeatureFlagsPatch.kt index c2da658aa..06f7d4437 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/OverrideFeatureFlagsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/featureflags/OverrideFeatureFlagsPatch.kt @@ -69,7 +69,7 @@ val overrideFeatureFlagsPatch = bytecodePatch( // This is equivalent to // String forcedValue = getValueOverride(feature) // if (forcedValue != null) return forcedValue - val getFeatureIndex = getFeatureValueFingerprint.patternMatch!!.startIndex + val getFeatureIndex = getFeatureValueFingerprint.instructionMatches.first().index getFeatureValueFingerprint.method.addInstructionsWithLabels( getFeatureIndex, """ diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/Fingerprints.kt index 11616fcc9..8d9f4cfd3 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/Fingerprints.kt @@ -6,7 +6,7 @@ import app.revanced.patcher.fingerprint // Fingerprint for the addQueryParam method from retrofit2 // https://github.com/square/retrofit/blob/trunk/retrofit/src/main/java/retrofit2/RequestBuilder.java#L186 // Injecting here allows modifying dynamically set query parameters -internal val addQueryParamFingerprint = fingerprint { +internal val addQueryParamFingerprint by fingerprint { parameters("Ljava/lang/String;", "Ljava/lang/String;", "Z") strings("Malformed URL. Base: ", ", Relative: ") } @@ -14,7 +14,7 @@ internal val addQueryParamFingerprint = fingerprint { // Fingerprint for the parseHttpMethodAndPath method from retrofit2 // https://github.com/square/retrofit/blob/ebf87b10997e2136af4d335276fa950221852c64/retrofit/src/main/java/retrofit2/RequestFactory.java#L270-L302 // Injecting here allows modifying the path/query params of API endpoints defined via annotations -internal val httpPathParserFingerprint = fingerprint { +internal val httpPathParserFingerprint by fingerprint { opcodes( Opcode.IPUT_OBJECT, Opcode.IPUT_BOOLEAN, diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/FixOldVersionsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/FixOldVersionsPatch.kt index dbe75d5f8..ad9f52f4b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/FixOldVersionsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/fixes/FixOldVersionsPatch.kt @@ -21,7 +21,7 @@ val fixOldVersionsPatch = bytecodePatch( // Remove the live query parameters from the path when it's specified via a @METHOD annotation. for (liveQueryParameter in liveQueryParameters) { httpPathParserFingerprint.method.addInstructions( - httpPathParserFingerprint.patternMatch!!.endIndex + 1, + httpPathParserFingerprint.instructionMatches.last().index + 1, """ # urlPath = urlPath.replace(liveQueryParameter, "") const-string p1, "$liveQueryParameter" diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/FilterTimelineObjectsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/FilterTimelineObjectsPatch.kt index c4ab799e8..5e8ad5c70 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/FilterTimelineObjectsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/FilterTimelineObjectsPatch.kt @@ -24,7 +24,7 @@ val filterTimelineObjectsPatch = bytecodePatch( dependsOn(sharedExtensionPatch) execute { - val filterInsertIndex = timelineFilterExtensionFingerprint.patternMatch!!.startIndex + val filterInsertIndex = timelineFilterExtensionFingerprint.instructionMatches.first().index timelineFilterExtensionFingerprint.method.apply { val addInstruction = getInstruction(filterInsertIndex + 1) @@ -47,7 +47,7 @@ val filterTimelineObjectsPatch = bytecodePatch( } } - mapOf( + arrayOf( timelineConstructorFingerprint to 1, postsResponseConstructorFingerprint to 2, ).forEach { (fingerprint, timelineObjectsRegister) -> diff --git a/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/Fingerprints.kt index b8ed3bfc4..75be30004 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/Fingerprints.kt @@ -6,7 +6,7 @@ import com.android.tools.smali.dexlib2.Opcode // This is the constructor of the PostsResponse class. // The same applies here as with the TimelineConstructorFingerprint. -internal val postsResponseConstructorFingerprint = fingerprint { +internal val postsResponseConstructorFingerprint by fingerprint { accessFlags(AccessFlags.CONSTRUCTOR, AccessFlags.PUBLIC) custom { method, classDef -> classDef.endsWith("/PostsResponse;") && method.parameters.size == 4 } } @@ -14,7 +14,7 @@ internal val postsResponseConstructorFingerprint = fingerprint { // This is the constructor of the Timeline class. // It receives the List as an argument with a @Json annotation, so this should be the first time // that the List is exposed in non-library code. -internal val timelineConstructorFingerprint = fingerprint { +internal val timelineConstructorFingerprint by fingerprint { strings("timelineObjectsList") custom { method, classDef -> classDef.endsWith("/Timeline;") && method.parameters[0].type == "Ljava/util/List;" @@ -24,7 +24,7 @@ internal val timelineConstructorFingerprint = fingerprint { // This fingerprints the extension TimelineFilterPatch.filterTimeline method. // The opcode fingerprint is searching for // if ("BLOCKED_OBJECT_DUMMY".equals(elementType)) iterator.remove(); -internal val timelineFilterExtensionFingerprint = fingerprint { +internal val timelineFilterExtensionFingerprint by fingerprint { opcodes( Opcode.CONST_STRING, // "BLOCKED_OBJECT_DUMMY" Opcode.INVOKE_VIRTUAL, // HashSet.add(^) diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/audio/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/audio/Fingerprints.kt index 21e9cb6d2..3bae02166 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/audio/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/audio/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.twitch.ad.audio import app.revanced.patcher.fingerprint -internal val audioAdsPresenterPlayFingerprint = fingerprint { +internal val audioAdsPresenterPlayFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("AudioAdsPlayerPresenter;") && method.name == "playAd" } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/Fingerprints.kt index 3e9853bd6..209f91d2b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.twitch.ad.embedded import app.revanced.patcher.fingerprint -internal val createsUsherClientFingerprint = fingerprint { +internal val createsUsherClientFingerprint by fingerprint { custom { method, _ -> method.name == "buildOkHttpClient" && method.definingClass.endsWith("Ltv/twitch/android/network/OkHttpClientFactory;") } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/AdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/AdPatch.kt index 48ecefba8..2cf8e5592 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/AdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/AdPatch.kt @@ -29,7 +29,7 @@ fun adPatch( classDefType: String, methodNames: Set, returnMethod: ReturnMethod, - ) = with(classBy { classDefType == it.type }?.mutableClass) { + ) = with(mutableClassByOrNull(classDefType)) { this ?: return false methods.filter { it.name in methodNames }.forEach { diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/video/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/video/Fingerprints.kt index d03449733..4bd8abb2a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/ad/video/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/ad/video/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.twitch.ad.video import app.revanced.patcher.fingerprint -internal val checkAdEligibilityLambdaFingerprint = fingerprint { +internal val checkAdEligibilityLambdaFingerprint by fingerprint { returns("Lio/reactivex/Single;") parameters("L") custom { method, _ -> @@ -11,7 +11,7 @@ internal val checkAdEligibilityLambdaFingerprint = fingerprint { } } -internal val contentConfigShowAdsFingerprint = fingerprint { +internal val contentConfigShowAdsFingerprint by fingerprint { returns("Z") parameters() custom { method, _ -> @@ -19,7 +19,7 @@ internal val contentConfigShowAdsFingerprint = fingerprint { } } -internal val getReadyToShowAdFingerprint = fingerprint { +internal val getReadyToShowAdFingerprint by fingerprint { returns("Ltv/twitch/android/core/mvp/presenter/StateAndAction;") parameters("L", "L") custom { method, _ -> diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/Fingerprints.kt index 21da99a5b..04ef72343 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/Fingerprints.kt @@ -3,21 +3,20 @@ package app.revanced.patches.twitch.chat.antidelete import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val chatUtilCreateDeletedSpanFingerprint = fingerprint { +internal val chatUtilCreateDeletedSpanFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("ChatUtil\$Companion;") && method.name == "createDeletedSpanFromChatMessageSpan" } } -internal val deletedMessageClickableSpanCtorFingerprint = fingerprint { +internal val deletedMessageClickableSpanCtorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") custom { _, classDef -> classDef.endsWith("DeletedMessageClickableSpan;") } } -internal val setHasModAccessFingerprint = fingerprint { +internal val setHasModAccessFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("DeletedMessageClickableSpan;") && method.name == "setHasModAccess" } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/Fingerprints.kt index 80abc9ac4..59986152c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.twitch.chat.autoclaim import app.revanced.patcher.fingerprint -internal val communityPointsButtonViewDelegateFingerprint = fingerprint { +internal val communityPointsButtonViewDelegateFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("CommunityPointsButtonViewDelegate;") && method.name == "showClaimAvailable" diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/debug/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/debug/Fingerprints.kt index 665180c19..49a8601f2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/debug/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/debug/Fingerprints.kt @@ -2,19 +2,19 @@ package app.revanced.patches.twitch.debug import app.revanced.patcher.fingerprint -internal val isDebugConfigEnabledFingerprint = fingerprint { +internal val isDebugConfigEnabledFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("/BuildConfigUtil;") && method.name == "isDebugConfigEnabled" } } -internal val isOmVerificationEnabledFingerprint = fingerprint { +internal val isOmVerificationEnabledFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("/BuildConfigUtil;") && method.name == "isOmVerificationEnabled" } } -internal val shouldShowDebugOptionsFingerprint = fingerprint { +internal val shouldShowDebugOptionsFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("/BuildConfigUtil;") && method.name == "shouldShowDebugOptions" } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitch/misc/settings/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitch/misc/settings/Fingerprints.kt index 43d5bb39b..f39c762e9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitch/misc/settings/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitch/misc/settings/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.twitch.misc.settings import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val menuGroupsOnClickFingerprint = fingerprint { +internal val menuGroupsOnClickFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC, AccessFlags.FINAL) returns("V") parameters("L", "L", "L") @@ -13,21 +13,21 @@ internal val menuGroupsOnClickFingerprint = fingerprint { } } -internal val menuGroupsUpdatedFingerprint = fingerprint { +internal val menuGroupsUpdatedFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("/SettingsMenuPresenter\$Event\$MenuGroupsUpdated;") && method.name == "" } } -internal val settingsActivityOnCreateFingerprint = fingerprint { +internal val settingsActivityOnCreateFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("/SettingsActivity;") && method.name == "onCreate" } } -internal val settingsMenuItemEnumFingerprint = fingerprint { +internal val settingsMenuItemEnumFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("/SettingsMenuItem;") && method.name == "" } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/Fingerprints.kt index dc100acb1..b01f75081 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val buildMediaOptionsSheetFingerprint = fingerprint { +internal val buildMediaOptionsSheetFingerprint by fingerprint { opcodes( Opcode.IF_EQ, Opcode.SGET_OBJECT, @@ -14,13 +14,12 @@ internal val buildMediaOptionsSheetFingerprint = fingerprint { strings("mediaEntity", "media_options_sheet") } -internal val constructMediaOptionsSheetFingerprint = fingerprint { +internal val constructMediaOptionsSheetFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") strings("captionsState") } -internal val showDownloadVideoUpsellBottomSheetFingerprint = fingerprint { +internal val showDownloadVideoUpsellBottomSheetFingerprint by fingerprint { returns("Z") strings("mediaEntity", "url") opcodes(Opcode.IF_EQZ) diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch.kt index 6f2b9c12c..945f0a47b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch.kt @@ -27,7 +27,7 @@ val unlockDownloadsPatch = bytecodePatch( // Allow downloads for non-premium users. showDownloadVideoUpsellBottomSheetFingerprint.patch { - val checkIndex = patternMatch!!.startIndex + val checkIndex = instructionMatches.first().index val register = method.getInstruction(checkIndex).registerA checkIndex to register @@ -42,25 +42,26 @@ val unlockDownloadsPatch = bytecodePatch( } // Make GIFs downloadable. - val patternMatch = buildMediaOptionsSheetFingerprint.patternMatch!! - buildMediaOptionsSheetFingerprint.method.apply { - val checkMediaTypeIndex = patternMatch.startIndex - val checkMediaTypeInstruction = getInstruction(checkMediaTypeIndex) + buildMediaOptionsSheetFingerprint.let { + it.method.apply { + val checkMediaTypeIndex = it.instructionMatches.first().index + val checkMediaTypeInstruction = getInstruction(checkMediaTypeIndex) - // Treat GIFs as videos. - addInstructionsWithLabels( - checkMediaTypeIndex + 1, - """ + // Treat GIFs as videos. + addInstructionsWithLabels( + checkMediaTypeIndex + 1, + """ const/4 v${checkMediaTypeInstruction.registerB}, 0x2 # GIF if-eq v${checkMediaTypeInstruction.registerA}, v${checkMediaTypeInstruction.registerB}, :video """, - ExternalLabel("video", getInstruction(patternMatch.endIndex)), - ) + ExternalLabel("video", getInstruction(it.instructionMatches.last().index)), + ) - // Remove media.isDownloadable check. - removeInstruction( - instructions.first { it.opcode == Opcode.IGET_BOOLEAN }.location.index + 1, - ) + // Remove media.isDownloadable check. + removeInstruction( + instructions.first { it.opcode == Opcode.IGET_BOOLEAN }.location.index + 1, + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/layout/viewcount/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/layout/viewcount/Fingerprints.kt index 625b6f0bb..199ef49c2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/layout/viewcount/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/layout/viewcount/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.twitter.layout.viewcount import app.revanced.patcher.fingerprint -internal val viewCountsEnabledFingerprint = fingerprint { +internal val viewCountsEnabledFingerprint by fingerprint { returns("Z") strings("view_counts_public_visibility_enabled") } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/DynamicColorPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/DynamicColorPatch.kt index 9d813b7ad..97347a8ee 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/DynamicColorPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/DynamicColorPatch.kt @@ -39,8 +39,7 @@ val dynamicColorPatch = resourcePatch( } document("res/values-v31/colors.xml").use { document -> - - mapOf( + arrayOf( "ps__twitter_blue" to "@color/twitter_blue", "ps__twitter_blue_pressed" to "@color/twitter_blue_fill_pressed", "twitter_blue" to "@android:color/system_accent1_400", @@ -60,7 +59,7 @@ val dynamicColorPatch = resourcePatch( } document("res/values-night-v31/colors.xml").use { document -> - mapOf( + arrayOf( "twitter_blue" to "@android:color/system_accent1_200", "twitter_blue_fill_pressed" to "@android:color/system_accent1_300", "twitter_blue_opacity_30" to "@android:color/system_accent1_50", diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/Fingerprints.kt index 337aeb567..1158df15d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.twitter.misc.hook.json import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.Opcode -internal val jsonHookPatchFingerprint = fingerprint { +internal val jsonHookPatchFingerprint by fingerprint { opcodes( Opcode.INVOKE_INTERFACE, // Add dummy hook to hooks list. // Add hooks to the hooks list. @@ -12,7 +12,7 @@ internal val jsonHookPatchFingerprint = fingerprint { custom { method, _ -> method.name == "" } } -internal val jsonInputStreamFingerprint = fingerprint { +internal val jsonInputStreamFingerprint by fingerprint { custom { method, _ -> if (method.parameterTypes.isEmpty()) { false @@ -22,6 +22,6 @@ internal val jsonInputStreamFingerprint = fingerprint { } } -internal val loganSquareFingerprint = fingerprint { +internal val loganSquareFingerprint by fingerprint { custom { _, classDef -> classDef.endsWith("LoganSquare;") } } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/JsonHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/JsonHookPatch.kt index 56785cae4..d3e95102f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/JsonHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/JsonHookPatch.kt @@ -22,7 +22,7 @@ fun addJsonHook( jsonHookPatchFingerprint.method.apply { // Insert hooks right before calling buildList. - val insertIndex = jsonHookPatchFingerprint.patternMatch!!.endIndex + val insertIndex = jsonHookPatchFingerprint.instructionMatches.last().index addInstructions( insertIndex, @@ -48,11 +48,9 @@ val jsonHookPatch = bytecodePatch( execute { jsonHookPatchFingerprint.apply { - // Make sure the extension is present. - val jsonHookPatch = classBy { classDef -> classDef.type == JSON_HOOK_PATCH_CLASS_DESCRIPTOR } - ?: throw PatchException("Could not find the extension.") + val jsonHookPatch = classBy(JSON_HOOK_PATCH_CLASS_DESCRIPTOR) - matchOrNull(jsonHookPatch.immutableClass) + matchOrNull(jsonHookPatch) ?: throw PatchException("Unexpected extension.") } @@ -61,7 +59,7 @@ val jsonHookPatch = bytecodePatch( .fields .firstOrNull { it.name == "JSON_FACTORY" } ?.type - .let { type -> classes.find { it.type == type } } + ?.let { type -> classes.classBy(type) } ?: throw PatchException("Could not find required class.") // Hook the methods first parameter. @@ -77,7 +75,7 @@ val jsonHookPatch = bytecodePatch( finalize { // Remove hooks.add(dummyHook). jsonHookPatchFingerprint.method.apply { - val addDummyHookIndex = jsonHookPatchFingerprint.patternMatch!!.endIndex - 2 + val addDummyHookIndex = jsonHookPatchFingerprint.instructionMatches.last().index - 2 removeInstructions(addDummyHookIndex, 2) } @@ -99,8 +97,8 @@ class JsonHook( internal var added = false init { - classBy { it.type == descriptor }?.let { - it.mutableClass.also { classDef -> + mutableClassBy(descriptor).let { + it.also { classDef -> if ( classDef.superclass != JSON_HOOK_CLASS_DESCRIPTOR || !classDef.fields.any { field -> field.name == "INSTANCE" } @@ -108,6 +106,6 @@ class JsonHook( throw InvalidClassException(classDef.type, "Not a hook class") } } - } ?: throw ClassNotFoundException("Failed to find hook class $descriptor") + } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt index bf3d9afd2..585acc49f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/ChangeLinkSharingDomainPatch.kt @@ -6,9 +6,9 @@ import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.patch.stringOption -import app.revanced.patches.shared.misc.mapping.get +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.twitter.misc.extension.sharedExtensionPatch import app.revanced.util.indexOfFirstLiteralInstructionOrThrow import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @@ -21,7 +21,7 @@ internal val changeLinkSharingDomainResourcePatch = resourcePatch { dependsOn(resourceMappingPatch) execute { - tweetShareLinkTemplateId = resourceMappings["string", "tweet_share_link"] + tweetShareLinkTemplateId = getResourceId(ResourceType.STRING, "tweet_share_link") } } @@ -55,7 +55,7 @@ val changeLinkSharingDomainPatch = bytecodePatch( execute { val replacementIndex = - linkSharingDomainFingerprint.stringMatches!!.first().index + linkSharingDomainFingerprint.stringMatches.first().index val domainRegister = linkSharingDomainFingerprint.method.getInstruction(replacementIndex).registerA diff --git a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/Fingerprints.kt index 0d5d0e6f8..abbf40e89 100644 --- a/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/twitter/misc/links/Fingerprints.kt @@ -4,28 +4,28 @@ import app.revanced.patcher.fingerprint import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags -internal val openLinkFingerprint = fingerprint { +internal val openLinkFingerprint by fingerprint { returns("V") parameters("Landroid/content/Context;", "Landroid/content/Intent;", "Landroid/os/Bundle;") } -internal val sanitizeSharingLinksFingerprint = fingerprint { +internal val sanitizeSharingLinksFingerprint by fingerprint { returns("Ljava/lang/String;") strings("", "shareParam", "sessionToken") } // Returns a shareable link string based on a tweet ID and a username. -internal val linkBuilderFingerprint = fingerprint { +internal val linkBuilderFingerprint by fingerprint { strings("/%1\$s/status/%2\$d") } // Gets Resource string for share link view available by pressing "Share via" button. -internal val linkResourceGetterFingerprint = fingerprint { +internal val linkResourceGetterFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters("Landroid/content/res/Resources;") literal { tweetShareLinkTemplateId } } -internal val linkSharingDomainFingerprint = fingerprint { +internal val linkSharingDomainFingerprint by fingerprint { strings("https://fxtwitter.com") } diff --git a/patches/src/main/kotlin/app/revanced/patches/vsco/misc/pro/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/vsco/misc/pro/Fingerprints.kt deleted file mode 100644 index 0809324c7..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/vsco/misc/pro/Fingerprints.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.vsco.misc.pro - -import app.revanced.patcher.fingerprint - -internal val revCatSubscriptionFingerprint = fingerprint { - returns("V") - strings("use_debug_subscription_settings") - custom { _, classDef -> - classDef.endsWith("/RevCatSubscriptionSettingsRepository;") - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/vsco/misc/pro/UnlockProPatch.kt b/patches/src/main/kotlin/app/revanced/patches/vsco/misc/pro/UnlockProPatch.kt deleted file mode 100644 index be0278dd9..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/vsco/misc/pro/UnlockProPatch.kt +++ /dev/null @@ -1,17 +0,0 @@ -package app.revanced.patches.vsco.misc.pro - -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated("This patch is deprecated because it does not work anymore and will be removed in the future.") -@Suppress("unused") -val unlockProPatch = bytecodePatch( - description = "Unlocks pro features.", -) { - compatibleWith("com.vsco.cam"("345")) - - execute { - // Set isSubscribed to true. - revCatSubscriptionFingerprint.method.addInstruction(0, "const p1, 0x1") - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/Fingerprints.kt index 6eb7bd176..03ff60e0c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.warnwetter.misc.firebasegetcert import app.revanced.patcher.fingerprint -internal val getMessagingCertFingerprint = fingerprint { +internal val getMessagingCertFingerprint by fingerprint { returns("Ljava/lang/String;") strings( "ContentValues", @@ -11,7 +11,7 @@ internal val getMessagingCertFingerprint = fingerprint { ) } -internal val getRegistrationCertFingerprint = fingerprint { +internal val getRegistrationCertFingerprint by fingerprint { returns("Ljava/lang/String;") strings( "FirebaseRemoteConfig", diff --git a/patches/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/Fingerprints.kt index d33880de7..024985638 100644 --- a/patches/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/Fingerprints.kt @@ -2,7 +2,7 @@ package app.revanced.patches.warnwetter.misc.promocode import app.revanced.patcher.fingerprint -internal val promoCodeUnlockFingerprint = fingerprint { +internal val promoCodeUnlockFingerprint by fingerprint { custom { method, classDef -> classDef.endsWith("PromoTokenVerification;") && method.name == "isValid" } diff --git a/patches/src/main/kotlin/app/revanced/patches/willhaben/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/willhaben/ads/Fingerprints.kt index e326c2682..19fdb02d8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/willhaben/ads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/willhaben/ads/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.willhaben.ads import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val adResolverFingerprint = fingerprint { +internal val adResolverFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters("L", "L") @@ -15,7 +15,7 @@ internal val adResolverFingerprint = fingerprint { ) } -internal val whAdViewInjectorFingerprint = fingerprint { +internal val whAdViewInjectorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L", "L", "L", "Z") diff --git a/patches/src/main/kotlin/app/revanced/patches/willhaben/ads/HideAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/willhaben/ads/HideAdsPatch.kt index b3dd1a3fc..0d7119a0b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/willhaben/ads/HideAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/willhaben/ads/HideAdsPatch.kt @@ -11,7 +11,7 @@ internal val hideAdsPatch = bytecodePatch( compatibleWith("at.willhaben") execute { - adResolverFingerprint.method.returnEarly() + adResolverFingerprint.method.returnEarly(null) whAdViewInjectorFingerprint.method.returnEarly() } } diff --git a/patches/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/Fingerprints.kt deleted file mode 100644 index f199f127c..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/Fingerprints.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.windyapp.misc.unlockpro - -import app.revanced.patcher.fingerprint - -internal val checkProFingerprint = fingerprint { - returns("I") - custom { method, classDef -> - classDef.endsWith("RawUserData;") && method.name == "isPro" - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/UnlockProPatch.kt b/patches/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/UnlockProPatch.kt deleted file mode 100644 index c0323c72e..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/UnlockProPatch.kt +++ /dev/null @@ -1,22 +0,0 @@ -package app.revanced.patches.windyapp.misc.unlockpro - -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated("This patch no longer works and will be removed in the future.") -@Suppress("unused") -val unlockProPatch = bytecodePatch( - description = "Unlocks all pro features.", -) { - compatibleWith("co.windyapp.android") - - execute { - checkProFingerprint.method.addInstructions( - 0, - """ - const/16 v0, 0x1 - return v0 - """, - ) - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/Fingerprints.kt index 254b440f3..8091108cf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/Fingerprints.kt @@ -8,7 +8,7 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal val fullScreenEngagementAdContainerFingerprint = fingerprint { +internal val fullScreenEngagementAdContainerFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt index e1d326610..8d952d3df 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt @@ -7,9 +7,9 @@ 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.fix.verticalscroll.verticalScrollPatch -import app.revanced.patches.shared.misc.mapping.get +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.ad.getpremium.hideGetPremiumPatch import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fixBackToExitGesturePatch @@ -57,8 +57,8 @@ private val hideAdsResourcePatch = resourcePatch { addLithoFilter("Lapp/revanced/extension/youtube/patches/components/AdsFilter;") - adAttributionId = resourceMappings["id", "ad_attribution"] - fullScreenEngagementAdContainer = resourceMappings["id", "fullscreen_engagement_ad_container"] + adAttributionId = getResourceId(ResourceType.ID, "ad_attribution") + fullScreenEngagementAdContainer = getResourceId(ResourceType.ID, "fullscreen_engagement_ad_container") } } @@ -125,8 +125,7 @@ val hideAdsPatch = bytecodePatch( // Hide the view val viewRegister = (this as Instruction35c).registerC - proxy(classDef) - .mutableClass + mutableClassBy(classDef) .findMutableMethodOf(method) .injectHideViewCall( insertIndex, diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/Fingerprints.kt index 7629d1760..284567fec 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val getPremiumViewFingerprint = fingerprint { +internal val getPremiumViewFingerprint by fingerprint { accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL) returns("V") parameters("I", "I") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt index bed7dba99..10e79d168 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt @@ -42,7 +42,7 @@ val hideGetPremiumPatch = bytecodePatch( ) getPremiumViewFingerprint.method.apply { - val startIndex = getPremiumViewFingerprint.patternMatch!!.startIndex + val startIndex = getPremiumViewFingerprint.instructionMatches.first().index val measuredWidthRegister = getInstruction(startIndex).registerA val measuredHeightInstruction = getInstruction(startIndex + 1) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/video/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/video/Fingerprints.kt index 91cc0e8df..2ccd68aa4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/video/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/video/Fingerprints.kt @@ -2,10 +2,9 @@ package app.revanced.patches.youtube.ad.video import app.revanced.patcher.fingerprint -internal val loadVideoAdsFingerprint = fingerprint { +internal val loadVideoAdsFingerprint by fingerprint { strings( "TriggerBundle doesn't have the required metadata specified by the trigger ", - "Tried to enter slot with no assigned slotAdapter", - "Trying to enter a slot when a slot of same type and physical position is already active. Its status: ", + "Ping migration no associated ping bindings for activated trigger: ", ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlPatch.kt index 047950331..fdf55ce0d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlPatch.kt @@ -15,7 +15,7 @@ import app.revanced.util.copyResources private val copyVideoUrlResourcePatch = resourcePatch { dependsOn( settingsPatch, - playerControlsResourcePatch, + playerControlsPatch, addResourcesPatch, ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/Fingerprints.kt index b25287590..d590b0c93 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/Fingerprints.kt @@ -1,22 +1,15 @@ package app.revanced.patches.youtube.interaction.dialog -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint +import app.revanced.patcher.methodCall -internal val createDialogFingerprint = fingerprint { - accessFlags(AccessFlags.PROTECTED) +internal val createDialogFingerprint by fingerprint { returns("V") parameters("L", "L", "Ljava/lang/String;") - opcodes( - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, // dialog.show() + instructions( + methodCall(smali = "Landroid/app/AlertDialog\$Builder;->setNegativeButton(ILandroid/content/DialogInterface\$OnClickListener;)Landroid/app/AlertDialog\$Builder;"), + methodCall(smali = "Landroid/app/AlertDialog\$Builder;->setOnCancelListener(Landroid/content/DialogInterface\$OnCancelListener;)Landroid/app/AlertDialog\$Builder;"), + methodCall(smali = "Landroid/app/AlertDialog\$Builder;->create()Landroid/app/AlertDialog;"), + methodCall(smali = "Landroid/app/AlertDialog;->show()V") ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt index 8c366e58b..21519fc80 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt @@ -11,6 +11,8 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/RemoveViewerDiscretionDialogPatch;" + val removeViewerDiscretionDialogPatch = bytecodePatch( name = "Remove viewer discretion dialog", description = "Adds an option to remove the dialog that appears when opening a video that has been age-restricted " + @@ -33,10 +35,6 @@ val removeViewerDiscretionDialogPatch = bytecodePatch( ) ) - val extensionMethodDescriptor = - "Lapp/revanced/extension/youtube/patches/RemoveViewerDiscretionDialogPatch;->" + - "confirmDialog(Landroid/app/AlertDialog;)V" - execute { addResources("youtube", "interaction.dialog.removeViewerDiscretionDialogPatch") @@ -44,14 +42,16 @@ val removeViewerDiscretionDialogPatch = bytecodePatch( SwitchPreference("revanced_remove_viewer_discretion_dialog"), ) - createDialogFingerprint.method.apply { - val showDialogIndex = implementation!!.instructions.lastIndex - 2 - val dialogRegister = getInstruction(showDialogIndex).registerC + createDialogFingerprint.let { + it.method.apply { + val showDialogIndex = it.instructionMatches.last().index + val dialogRegister = getInstruction(showDialogIndex).registerC - replaceInstructions( - showDialogIndex, - "invoke-static { v$dialogRegister }, $extensionMethodDescriptor", - ) + replaceInstructions( + showDialogIndex, + "invoke-static { v$dialogRegister }, $EXTENSION_CLASS_DESCRIPTOR->confirmDialog(Landroid/app/AlertDialog;)V", + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/DisableChapterSkipDoubleTapPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/DisableChapterSkipDoubleTapPatch.kt index 9672ef9a2..38b742cf8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/DisableChapterSkipDoubleTapPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/DisableChapterSkipDoubleTapPatch.kt @@ -41,7 +41,7 @@ val disableDoubleTapActionsPatch = bytecodePatch( SwitchPreference("revanced_disable_chapter_skip_double_tap"), ) - val doubleTapInfoGetSeekSourceFingerprint = fingerprint { + val doubleTapInfoGetSeekSourceFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters("Z") returns(seekTypeEnumFingerprint.originalClassDef.type) @@ -77,8 +77,3 @@ val disableDoubleTapActionsPatch = bytecodePatch( ) } } - -@Deprecated("Patch was renamed", ReplaceWith("disableDoubleTapActionsPatch")) -val disableChapterSkipDoubleTapPatch = bytecodePatch { - dependsOn(disableDoubleTapActionsPatch) -} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/Fingerprints.kt index 4524a6853..759dcd3df 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/doubletap/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.youtube.interaction.doubletap import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val seekTypeEnumFingerprint = fingerprint { +internal val seekTypeEnumFingerprint by fingerprint { accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) strings( "SEEK_SOURCE_SEEK_TO_NEXT_CHAPTER", @@ -11,7 +11,7 @@ internal val seekTypeEnumFingerprint = fingerprint { ) } -internal val doubleTapInfoCtorFingerprint = fingerprint { +internal val doubleTapInfoCtorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameters( "Landroid/view/MotionEvent;", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt index 82f19f81a..5bd5fbba9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt @@ -14,7 +14,6 @@ import app.revanced.patches.youtube.misc.playercontrols.addBottomControl import app.revanced.patches.youtube.misc.playercontrols.initializeBottomControl import app.revanced.patches.youtube.misc.playercontrols.injectVisibilityCheckCall import app.revanced.patches.youtube.misc.playercontrols.playerControlsPatch -import app.revanced.patches.youtube.misc.playercontrols.playerControlsResourcePatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint @@ -24,7 +23,7 @@ import app.revanced.util.copyResources private val downloadsResourcePatch = resourcePatch { dependsOn( - playerControlsResourcePatch, + playerControlsPatch, settingsPatch, addResourcesPatch, ) @@ -90,7 +89,7 @@ val downloadsPatch = bytecodePatch( // Main activity is used to launch downloader intent. mainActivityOnCreateFingerprint.method.addInstruction( 1, - "invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->activityCreated(Landroid/app/Activity;)V" + "invoke-static/range { p0 .. p0 }, ${EXTENSION_CLASS_DESCRIPTOR}->setMainActivity(Landroid/app/Activity;)V" ) offlineVideoEndpointFingerprint.method.apply { diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/Fingerprints.kt index f10fc8e83..abd9a1e12 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/Fingerprints.kt @@ -1,9 +1,10 @@ package app.revanced.patches.youtube.interaction.downloads -import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint +import app.revanced.patcher.string +import com.android.tools.smali.dexlib2.AccessFlags -internal val offlineVideoEndpointFingerprint = fingerprint { +internal val offlineVideoEndpointFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters( @@ -12,5 +13,7 @@ internal val offlineVideoEndpointFingerprint = fingerprint { "Ljava/lang/String", // VideoId "L", ) - strings("Object is not an offlineable video: ") + instructions( + string("Object is not an offlineable video: ") + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt index 162b69090..6ee07c811 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt @@ -11,8 +11,6 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.util.findFreeRegister -import app.revanced.util.indexOfFirstInstructionOrThrow -import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference @@ -37,38 +35,46 @@ val enableSeekbarTappingPatch = bytecodePatch( // Find the required methods to tap the seekbar. val seekbarTappingMethods = onTouchEventHandlerFingerprint.let { - fun getMethodReference(index: Int) = it.method.getInstruction(index) + fun getReference(index: Int) = it.method.getInstruction(index) .reference as MethodReference listOf( - getMethodReference(it.patternMatch!!.startIndex), - getMethodReference(it.patternMatch!!.endIndex) + getReference(it.instructionMatches.first().index), + getReference(it.instructionMatches.last().index) ) } - seekbarTappingFingerprint.method.apply { - val pointIndex = indexOfNewPointInstruction(this) - val invokeIndex = indexOfFirstInstructionOrThrow(pointIndex, Opcode.INVOKE_VIRTUAL) - val insertIndex = invokeIndex + 1 + seekbarTappingFingerprint.let { + val insertIndex = it.instructionMatches.last().index + 1 - val thisInstanceRegister = getInstruction(invokeIndex).registerC - val xAxisRegister = this.getInstruction(pointIndex).registerD - val freeRegister = findFreeRegister(insertIndex, thisInstanceRegister, xAxisRegister) + it.method.apply { + val thisInstanceRegister = getInstruction( + insertIndex - 1 + ).registerC - val oMethod = seekbarTappingMethods[0] - val nMethod = seekbarTappingMethods[1] + val xAxisRegister = this.getInstruction( + it.instructionMatches[2].index + ).registerD - addInstructionsWithLabels( - insertIndex, - """ - invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->seekbarTappingEnabled()Z - move-result v$freeRegister - if-eqz v$freeRegister, :disabled - invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $oMethod - invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $nMethod - """, - ExternalLabel("disabled", getInstruction(insertIndex)), - ) + val freeRegister = findFreeRegister( + insertIndex, thisInstanceRegister, xAxisRegister + ) + + val oMethod = seekbarTappingMethods[0] + val nMethod = seekbarTappingMethods[1] + + addInstructionsWithLabels( + insertIndex, + """ + invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->seekbarTappingEnabled()Z + move-result v$freeRegister + if-eqz v$freeRegister, :disabled + invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $oMethod + invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $nMethod + """, + ExternalLabel("disabled", getInstruction(insertIndex)), + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt index 8c5dce555..5ee27ab78 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt @@ -42,7 +42,7 @@ val enableSlideToSeekPatch = bytecodePatch( // Restore the behaviour to slide to seek. - val checkIndex = slideToSeekFingerprint.patternMatch!!.startIndex + val checkIndex = slideToSeekFingerprint.instructionMatches.first().index val checkReference = slideToSeekFingerprint.method.getInstruction(checkIndex) .getReference()!! @@ -75,7 +75,7 @@ val enableSlideToSeekPatch = bytecodePatch( if (is_19_17_or_greater) { disableFastForwardGestureFingerprint.let { it.method.apply { - val targetIndex = it.patternMatch!!.endIndex + val targetIndex = it.instructionMatches.last().index val targetRegister = getInstruction(targetIndex).registerA addInstructions( @@ -88,17 +88,19 @@ val enableSlideToSeekPatch = bytecodePatch( } } } else { - disableFastForwardLegacyFingerprint.method.apply { - val insertIndex = disableFastForwardLegacyFingerprint.patternMatch!!.endIndex + 1 - val targetRegister = getInstruction(insertIndex).registerA + disableFastForwardLegacyFingerprint.let { + it.method.apply { + val insertIndex = it.instructionMatches.last().index + 1 + val targetRegister = getInstruction(insertIndex).registerA - addInstructions( - insertIndex, - """ - invoke-static { v$targetRegister }, $extensionMethodDescriptor - move-result v$targetRegister - """, - ) + addInstructions( + insertIndex, + """ + invoke-static { v$targetRegister }, $extensionMethodDescriptor + move-result v$targetRegister + """, + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt index 0b7bf052a..e8a74ee4f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/Fingerprints.kt @@ -1,48 +1,61 @@ package app.revanced.patches.youtube.interaction.seekbar +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint -import app.revanced.util.containsLiteralInstruction +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.newInstance +import app.revanced.patcher.opcode +import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater +import app.revanced.patches.youtube.misc.playservice.is_19_47_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_19_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_20_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_31_or_greater import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionReversed +import app.revanced.util.indexOfFirstInstruction import app.revanced.util.literal 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 +import com.android.tools.smali.dexlib2.iface.reference.StringReference -internal val swipingUpGestureParentFingerprint = fingerprint { +internal val swipingUpGestureParentFingerprint by fingerprint { returns("Z") parameters() - literal { 45379021 } + instructions( + literal(45379021) // Swipe up fullscreen feature flag + ) } /** * Resolves using the class found in [swipingUpGestureParentFingerprint]. */ -internal val showSwipingUpGuideFingerprint = fingerprint { +internal val showSwipingUpGuideFingerprint by fingerprint { accessFlags(AccessFlags.FINAL) returns("Z") parameters() - literal { 1 } + instructions( + literal(1) + ) } /** * Resolves using the class found in [swipingUpGestureParentFingerprint]. */ -internal val allowSwipingUpGestureFingerprint = fingerprint { +internal val allowSwipingUpGestureFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L") } -internal val disableFastForwardLegacyFingerprint = fingerprint { +internal val disableFastForwardLegacyFingerprint by fingerprint { returns("Z") parameters() opcodes(Opcode.MOVE_RESULT) - literal { 45411330 } + // Intent start flag only used in the subscription activity + literal {45411330} } -internal val disableFastForwardGestureFingerprint = fingerprint { +internal val disableFastForwardGestureFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() @@ -57,7 +70,27 @@ internal val disableFastForwardGestureFingerprint = fingerprint { } } -internal val onTouchEventHandlerFingerprint = fingerprint { +internal val customTapAndHoldFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters() + instructions( + literal(2.0f) + ) + custom { method, _ -> + // Code is found in different methods with different strings. + val findSearchLandingKey = (is_19_34_or_greater && !is_19_47_or_greater) + || (is_20_19_or_greater && !is_20_20_or_greater) || is_20_31_or_greater + + method.name == "run" && method.indexOfFirstInstruction { + val string = getReference()?.string + string == "Failed to easy seek haptics vibrate." + || (findSearchLandingKey && string == "search_landing_cache_key") + } >= 0 + } +} + +internal val onTouchEventHandlerFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.PUBLIC) returns("Z") parameters("L") @@ -80,24 +113,25 @@ internal val onTouchEventHandlerFingerprint = fingerprint { custom { method, _ -> method.name == "onTouchEvent" } } -internal val seekbarTappingFingerprint = fingerprint { +internal val seekbarTappingFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") - parameters("L") - custom { method, _ -> - method.name == "onTouchEvent" - && method.containsLiteralInstruction(Integer.MAX_VALUE.toLong()) - && indexOfNewPointInstruction(method) >= 0 - } + parameters("Landroid/view/MotionEvent;") + instructions( + literal(Int.MAX_VALUE), + + newInstance("Landroid/graphics/Point;"), + methodCall(smali = "Landroid/graphics/Point;->(II)V", maxAfter = 0), + methodCall(smali = "Lj\$/util/Optional;->of(Ljava/lang/Object;)Lj\$/util/Optional;", maxAfter = 0), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0), + fieldAccess(opcode = Opcode.IPUT_OBJECT, type = "Lj\$/util/Optional;", maxAfter = 0), + + opcode(Opcode.INVOKE_VIRTUAL, maxAfter = 10) + ) + custom { method, _ -> method.name == "onTouchEvent" } } -internal fun indexOfNewPointInstruction(method: Method) = method.indexOfFirstInstructionReversed { - val reference = getReference() - reference?.definingClass == "Landroid/graphics/Point;" - && reference.name == "" -} - -internal val slideToSeekFingerprint = fingerprint { +internal val slideToSeekFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returns("V") parameters("Landroid/view/View;", "F") @@ -110,9 +144,20 @@ internal val slideToSeekFingerprint = fingerprint { literal { 67108864 } } -internal val fullscreenSeekbarThumbnailsQualityFingerprint = fingerprint { +internal val fullscreenSeekbarThumbnailsQualityFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() - literal { 45399684L } + instructions( + literal(45399684L) // Video stream seekbar thumbnails feature flag. + ) +} + +internal val fullscreenLargeSeekbarFeatureFlagFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("Z") + parameters() + instructions( + literal(45691569) + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/HideSeekbarPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/HideSeekbarPatch.kt index ddf21dd85..d057f9170 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/HideSeekbarPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/HideSeekbarPatch.kt @@ -7,10 +7,15 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.seekbar.seekbarColorPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch +import app.revanced.patches.youtube.misc.playservice.is_20_28_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.shared.seekbarFingerprint import app.revanced.patches.youtube.shared.seekbarOnDrawFingerprint +import app.revanced.util.insertLiteralOverride + +private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/HideSeekbarPatch;" val hideSeekbarPatch = bytecodePatch( description = "Adds an option to hide the seekbar.", @@ -20,6 +25,7 @@ val hideSeekbarPatch = bytecodePatch( settingsPatch, seekbarColorPatch, addResourcesPatch, + versionCheckPatch ) execute { @@ -28,19 +34,29 @@ val hideSeekbarPatch = bytecodePatch( PreferenceScreen.SEEKBAR.addPreferences( SwitchPreference("revanced_hide_seekbar"), SwitchPreference("revanced_hide_seekbar_thumbnail"), + SwitchPreference("revanced_fullscreen_large_seekbar"), ) seekbarOnDrawFingerprint.match(seekbarFingerprint.originalClassDef).method.addInstructionsWithLabels( 0, """ const/4 v0, 0x0 - invoke-static { }, Lapp/revanced/extension/youtube/patches/HideSeekbarPatch;->hideSeekbar()Z + invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideSeekbar()Z move-result v0 if-eqz v0, :hide_seekbar return-void :hide_seekbar nop - """, + """ ) + + if (is_20_28_or_greater) { + fullscreenLargeSeekbarFeatureFlagFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->useFullscreenLargeSeekbar(Z)Z" + ) + } + } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/SeekbarThumbnailsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/SeekbarThumbnailsPatch.kt index b502be1ae..66a79003f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/SeekbarThumbnailsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/SeekbarThumbnailsPatch.kt @@ -13,6 +13,7 @@ import app.revanced.patches.youtube.misc.playservice.is_19_17_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.settings.PreferenceScreen +import java.util.logging.Logger private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/SeekbarThumbnailsPatch;" diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/Fingerprints.kt index e1161ea13..2c7dc336b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/Fingerprints.kt @@ -1,10 +1,10 @@ package app.revanced.patches.youtube.interaction.swipecontrols import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal import com.android.tools.smali.dexlib2.AccessFlags -internal val swipeControlsHostActivityFingerprint = fingerprint { +internal val swipeControlsHostActivityFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameters() custom { method, _ -> @@ -12,12 +12,9 @@ internal val swipeControlsHostActivityFingerprint = fingerprint { } } -internal const val SWIPE_CHANGE_VIDEO_FEATURE_FLAG = 45631116L - -internal val swipeChangeVideoFingerprint = fingerprint { +internal val swipeChangeVideoFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - parameters("L") - literal { - SWIPE_CHANGE_VIDEO_FEATURE_FLAG - } + instructions( + literal(45631116L) // Swipe to change fullscreen video feature flag. + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt index dd83a9549..f0efb9cc9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsPatch.kt @@ -12,6 +12,9 @@ import app.revanced.patches.shared.misc.settings.preference.TextPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch import app.revanced.patches.youtube.misc.playservice.is_19_43_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_22_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_34_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.shared.mainActivityConstructorFingerprint @@ -25,12 +28,16 @@ private val swipeControlsResourcePatch = resourcePatch { dependsOn( settingsPatch, addResourcesPatch, + versionCheckPatch, ) execute { addResources("youtube", "interaction.swipecontrols.swipeControlsResourcePatch") - if (is_19_43_or_greater) { + // If fullscreen swipe is enabled in newer versions the app can crash. + // It likely is caused by conflicting experimental flags that are never enabled together. + // Flag was completely removed in 20.34+ + if (is_19_43_or_greater && !is_20_22_or_greater) { PreferenceScreen.SWIPE_CONTROLS.addPreferences( SwitchPreference("revanced_swipe_change_video") ) @@ -124,11 +131,13 @@ val swipeControlsPatch = bytecodePatch( // region patch to enable/disable swipe to change video. - if (is_19_43_or_greater) { - swipeChangeVideoFingerprint.method.insertLiteralOverride( - SWIPE_CHANGE_VIDEO_FEATURE_FLAG, - "$EXTENSION_CLASS_DESCRIPTOR->allowSwipeChangeVideo(Z)Z" - ) + if (is_19_43_or_greater && !is_20_34_or_greater) { + swipeChangeVideoFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.last().index, + "$EXTENSION_CLASS_DESCRIPTOR->allowSwipeChangeVideo(Z)Z" + ) + } } // endregion diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt index ff7ee248f..29e9b7af2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt @@ -53,7 +53,7 @@ val autoCaptionsPatch = bytecodePatch( """ ) - mapOf( + arrayOf( startVideoInformerFingerprint to 0, storyboardRendererDecoderRecommendedLevelFingerprint to 1 ).forEach { (fingerprint, enabled) -> diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/Fingerprints.kt index c657b72ec..3ecbb437e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val startVideoInformerFingerprint = fingerprint { +internal val startVideoInformerFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") opcodes( @@ -14,14 +14,14 @@ internal val startVideoInformerFingerprint = fingerprint { strings("pc") } -internal val storyboardRendererDecoderRecommendedLevelFingerprint = fingerprint { +internal val storyboardRendererDecoderRecommendedLevelFingerprint by fingerprint { returns("V") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters("L") strings("#-1#") } -internal val subtitleTrackFingerprint = fingerprint { +internal val subtitleTrackFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt index 1eac1fb6c..94e804575 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt @@ -20,7 +20,7 @@ private val iconResourceFileNames = arrayOf( "ic_launcher_round", ).map { "$it.png" }.toTypedArray() -private val iconResourceFileNamesNew = mapOf( +private val iconResourceFileNamesNew = arrayOf( "adaptiveproduct_youtube_foreground_color_108" to "adaptiveproduct_youtube_2024_q4_foreground_color_108", "adaptiveproduct_youtube_background_color_108" to "adaptiveproduct_youtube_2024_q4_background_color_108", ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt index cd2045550..e2833e5b7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt @@ -9,9 +9,9 @@ import app.revanced.patcher.patch.stringOption import app.revanced.patcher.util.Document 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.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.util.ResourceGroup @@ -38,7 +38,7 @@ private val changeHeaderBytecodePatch = bytecodePatch { "yt_ringo2_premium_wordmark_header" ).forEach { resource -> variants.forEach { theme -> - resourceMappings["drawable", resource + "_" + theme] + getResourceId(ResourceType.DRAWABLE, resource + "_" + theme) } } @@ -46,7 +46,7 @@ private val changeHeaderBytecodePatch = bytecodePatch { "ytWordmarkHeader", "ytPremiumWordmarkHeader" ).forEach { resourceName -> - val resourceId = resourceMappings["attr", resourceName] + val resourceId = getResourceId(ResourceType.ATTR, resourceName) forEachLiteralValueInstruction(resourceId) { literalIndex -> val register = getInstruction(literalIndex).registerA diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt index 7b368f31f..c8b802361 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt @@ -8,6 +8,8 @@ import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPref import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch +import app.revanced.patches.youtube.misc.playservice.is_20_22_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen val hideButtonsPatch = resourcePatch( @@ -18,6 +20,7 @@ val hideButtonsPatch = resourcePatch( resourceMappingPatch, lithoFilterPatch, addResourcesPatch, + versionCheckPatch, ) compatibleWith( @@ -34,24 +37,33 @@ val hideButtonsPatch = resourcePatch( execute { addResources("youtube", "layout.buttons.action.hideButtonsPatch") + val preferences = mutableSetOf( + SwitchPreference("revanced_disable_like_subscribe_glow"), + SwitchPreference("revanced_hide_download_button"), + SwitchPreference("revanced_hide_like_dislike_button"), + SwitchPreference("revanced_hide_save_button"), + ) + + if (!is_20_22_or_greater) { + // FIXME: 20.22+ filtering of the action buttons doesn't work because + // the buffer is the same for all buttons. + preferences.addAll(listOf( + SwitchPreference("revanced_hide_hype_button"), + SwitchPreference("revanced_hide_ask_button"), + SwitchPreference("revanced_hide_clip_button"), + SwitchPreference("revanced_hide_promote_button"), + SwitchPreference("revanced_hide_remix_button"), + SwitchPreference("revanced_hide_report_button"), + SwitchPreference("revanced_hide_share_button"), + SwitchPreference("revanced_hide_stop_ads_button"), + SwitchPreference("revanced_hide_thanks_button"), + )) + } + PreferenceScreen.PLAYER.addPreferences( PreferenceScreenPreference( "revanced_hide_buttons_screen", - preferences = setOf( - SwitchPreference("revanced_disable_like_subscribe_glow"), - SwitchPreference("revanced_hide_ask_button"), - SwitchPreference("revanced_hide_clip_button"), - SwitchPreference("revanced_hide_download_button"), - SwitchPreference("revanced_hide_hype_button"), - SwitchPreference("revanced_hide_like_dislike_button"), - SwitchPreference("revanced_hide_promote_button"), - SwitchPreference("revanced_hide_remix_button"), - SwitchPreference("revanced_hide_report_button"), - SwitchPreference("revanced_hide_save_button"), - SwitchPreference("revanced_hide_share_button"), - SwitchPreference("revanced_hide_stop_ads_button"), - SwitchPreference("revanced_hide_thanks_button"), - ) + preferences = preferences ) ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/Fingerprints.kt index a4e65eb28..49868a731 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/Fingerprints.kt @@ -1,53 +1,68 @@ package app.revanced.patches.youtube.layout.buttons.navigation -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patcher.string +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode -internal const val ANDROID_AUTOMOTIVE_STRING = "Android Automotive" - -internal val addCreateButtonViewFingerprint = fingerprint { - strings("Android Wear", ANDROID_AUTOMOTIVE_STRING) +internal val addCreateButtonViewFingerprint by fingerprint { + instructions( + string("Android Wear"), + opcode(Opcode.IF_EQZ), + string("Android Automotive", maxAfter = 0), + ) } -internal val createPivotBarFingerprint = fingerprint { +internal val createPivotBarFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") parameters( "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;", "Landroid/widget/TextView;", "Ljava/lang/CharSequence;", ) - opcodes( - Opcode.INVOKE_VIRTUAL, - Opcode.RETURN_VOID, + instructions( + methodCall(definingClass = "Landroid/widget/TextView;", name = "setText"), + opcode(Opcode.RETURN_VOID) ) } -internal const val TRANSLUCENT_NAVIGATION_STATUS_BAR_FEATURE_FLAG = 45400535L - -internal val translucentNavigationStatusBarFeatureFlagFingerprint = fingerprint { +internal val animatedNavigationTabsFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") - literal { TRANSLUCENT_NAVIGATION_STATUS_BAR_FEATURE_FLAG } + instructions( + literal(45680008L) + ) } -internal const val TRANSLUCENT_NAVIGATION_BUTTONS_FEATURE_FLAG = 45630927L - -internal val translucentNavigationButtonsFeatureFlagFingerprint = fingerprint { +internal val translucentNavigationStatusBarFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("V") - literal { TRANSLUCENT_NAVIGATION_BUTTONS_FEATURE_FLAG } + returns("Z") + instructions( + literal(45400535L) // Translucent status bar feature flag. + ) } /** - * The device on screen back/home/recent buttons. + * YouTube nav buttons. */ -internal const val TRANSLUCENT_NAVIGATION_BUTTONS_SYSTEM_FEATURE_FLAG = 45632194L +internal val translucentNavigationButtonsFeatureFlagFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + instructions( + literal(45630927L) // Translucent navigation bar buttons feature flag. + ) +} -internal val translucentNavigationButtonsSystemFeatureFlagFingerprint = fingerprint { +/** + * Device on screen back/home/recent buttons. + */ +internal val translucentNavigationButtonsSystemFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") - literal { TRANSLUCENT_NAVIGATION_BUTTONS_SYSTEM_FEATURE_FLAG } + instructions( + literal(45632194L) // Translucent system buttons feature flag. + ) } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt index b59ec3f38..1f1cf7850 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt @@ -13,15 +13,13 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.navigation.hookNavigationButtonCreated import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_15_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.insertLiteralOverride 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.reference.MethodReference private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/NavigationButtonsPatch;" @@ -71,6 +69,12 @@ val navigationButtonsPatch = bytecodePatch( ) } + if (is_20_15_or_greater) { + PreferenceScreen.GENERAL_LAYOUT.addPreferences( + SwitchPreference("revanced_navigation_bar_animations") + ) + } + PreferenceScreen.GENERAL_LAYOUT.addPreferences( PreferenceScreenPreference( key = "revanced_navigation_buttons_screen", @@ -80,59 +84,70 @@ val navigationButtonsPatch = bytecodePatch( ) // Switch create with notifications button. - addCreateButtonViewFingerprint.method.apply { - val stringIndex = addCreateButtonViewFingerprint.stringMatches!!.find { match -> - match.string == ANDROID_AUTOMOTIVE_STRING - }!!.index + addCreateButtonViewFingerprint.let { + it.method.apply { + val conditionalCheckIndex = it.instructionMatches[1].index + val conditionRegister = + getInstruction(conditionalCheckIndex).registerA - val conditionalCheckIndex = stringIndex - 1 - val conditionRegister = - getInstruction(conditionalCheckIndex).registerA - - addInstructions( - conditionalCheckIndex, - """ - invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->switchCreateWithNotificationButton()Z - move-result v$conditionRegister - """, - ) + addInstructions( + conditionalCheckIndex, + """ + invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->switchCreateWithNotificationButton()Z + move-result v$conditionRegister + """, + ) + } } // Hide navigation button labels. - createPivotBarFingerprint.method.apply { - val setTextIndex = indexOfFirstInstructionOrThrow { - getReference()?.name == "setText" + createPivotBarFingerprint.let { + it.method.apply { + val setTextIndex = it.instructionMatches.first().index + val targetRegister = getInstruction(setTextIndex).registerC + + addInstruction( + setTextIndex, + "invoke-static { v$targetRegister }, " + + "$EXTENSION_CLASS_DESCRIPTOR->hideNavigationButtonLabels(Landroid/widget/TextView;)V", + ) } - - val targetRegister = getInstruction(setTextIndex).registerC - - addInstruction( - setTextIndex, - "invoke-static { v$targetRegister }, " + - "$EXTENSION_CLASS_DESCRIPTOR->hideNavigationButtonLabels(Landroid/widget/TextView;)V", - ) } // Hook navigation button created, in order to hide them. hookNavigationButtonCreated(EXTENSION_CLASS_DESCRIPTOR) - // Force on/off translucent effect on status bar and navigation buttons. if (is_19_25_or_greater) { - translucentNavigationStatusBarFeatureFlagFingerprint.method.insertLiteralOverride( - TRANSLUCENT_NAVIGATION_STATUS_BAR_FEATURE_FLAG, - "$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationStatusBar(Z)Z", - ) + translucentNavigationStatusBarFeatureFlagFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationStatusBar(Z)Z", + ) + } - translucentNavigationButtonsFeatureFlagFingerprint.method.insertLiteralOverride( - TRANSLUCENT_NAVIGATION_BUTTONS_FEATURE_FLAG, - "$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationButtons(Z)Z", - ) + translucentNavigationButtonsFeatureFlagFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationButtons(Z)Z", + ) + } - translucentNavigationButtonsSystemFeatureFlagFingerprint.method.insertLiteralOverride( - TRANSLUCENT_NAVIGATION_BUTTONS_SYSTEM_FEATURE_FLAG, - "$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationButtons(Z)Z", - ) + translucentNavigationButtonsSystemFeatureFlagFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationButtons(Z)Z", + ) + } + } + + if (is_20_15_or_greater) { + animatedNavigationTabsFeatureFlagFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->useAnimatedNavigationButtons(Z)Z" + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/Fingerprints.kt index 7cc63f0fe..128ce0e96 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/Fingerprints.kt @@ -1,30 +1,39 @@ package app.revanced.patches.youtube.layout.buttons.overlay import app.revanced.patcher.fingerprint -import app.revanced.util.containsLiteralInstruction -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import com.android.tools.smali.dexlib2.AccessFlags -internal val playerControlsPreviousNextOverlayTouchFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("V") - strings("1.0x") - custom { methodDef, _ -> - methodDef.containsLiteralInstruction(playerControlPreviousButtonTouchArea) && - methodDef.containsLiteralInstruction(playerControlNextButtonTouchArea) - } -} - -internal val mediaRouteButtonFingerprint = fingerprint { +internal val mediaRouteButtonFingerprint by fingerprint { parameters("I") custom { methodDef, _ -> methodDef.definingClass.endsWith("/MediaRouteButton;") && methodDef.name == "setVisibility" } } -internal val inflateControlsGroupLayoutStubFingerprint = fingerprint { +internal val castButtonPlayerFeatureFlagFingerprint by fingerprint { + returns("Z") + instructions( + literal(45690091) + ) +} + +internal val castButtonActionFeatureFlagFingerprint by fingerprint { + returns("Z") + instructions( + literal(45690090) + ) +} + +internal val inflateControlsGroupLayoutStubFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters() returns("V") - literal { controlsButtonGroupLayoutStub } + instructions( + resourceLiteral(ResourceType.ID, "youtube_controls_button_group_layout_stub"), + methodCall(name = "inflate") + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/HidePlayerOverlayButtonsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/HidePlayerOverlayButtonsPatch.kt index a890cf2be..239fdd37d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/HidePlayerOverlayButtonsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/overlay/HidePlayerOverlayButtonsPatch.kt @@ -5,42 +5,28 @@ 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.patch.bytecodePatch -import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.util.smali.ExternalLabel 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.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch +import app.revanced.patches.youtube.misc.playservice.is_20_28_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.shared.layoutConstructorFingerprint import app.revanced.patches.youtube.shared.subtitleButtonControllerFingerprint -import app.revanced.util.* +import app.revanced.util.findFreeRegister +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.indexOfFirstResourceIdOrThrow +import app.revanced.util.insertLiteralOverride import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal var playerControlPreviousButtonTouchArea = -1L - private set -internal var playerControlNextButtonTouchArea = -1L - private set -internal var controlsButtonGroupLayoutStub = -1L - private set - -private val hidePlayerOverlayButtonsResourcePatch = resourcePatch { - dependsOn(resourceMappingPatch) - - execute { - playerControlPreviousButtonTouchArea = resourceMappings["id", "player_control_previous_button_touch_area"] - playerControlNextButtonTouchArea = resourceMappings["id", "player_control_next_button_touch_area"] - controlsButtonGroupLayoutStub = resourceMappings["id", "youtube_controls_button_group_layout_stub"] - } -} - private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/HidePlayerOverlayButtonsPatch;" @@ -53,7 +39,8 @@ val hidePlayerOverlayButtonsPatch = bytecodePatch( sharedExtensionPatch, settingsPatch, addResourcesPatch, - hidePlayerOverlayButtonsResourcePatch, + resourceMappingPatch, // Used by fingerprints. + versionCheckPatch ) compatibleWith( @@ -80,21 +67,19 @@ val hidePlayerOverlayButtonsPatch = bytecodePatch( // region Hide player next/previous button. - playerControlsPreviousNextOverlayTouchFingerprint.method.apply { - val resourceIndex = indexOfFirstLiteralInstructionOrThrow(playerControlPreviousButtonTouchArea) + layoutConstructorFingerprint.let { + it.clearMatch() // Fingerprint is shared with other patches. - val insertIndex = indexOfFirstInstructionOrThrow(resourceIndex) { - opcode == Opcode.INVOKE_STATIC && - getReference()?.parameterTypes?.firstOrNull() == "Landroid/view/View;" + it.method.apply { + val insertIndex = it.instructionMatches.last().index + val viewRegister = getInstruction(insertIndex).registerC + + addInstruction( + insertIndex, + "invoke-static { v$viewRegister }, $EXTENSION_CLASS_DESCRIPTOR" + + "->hidePreviousNextButtons(Landroid/view/View;)V", + ) } - - val viewRegister = getInstruction(insertIndex).registerC - - addInstruction( - insertIndex, - "invoke-static { v$viewRegister }, $EXTENSION_CLASS_DESCRIPTOR" + - "->hidePreviousNextButtons(Landroid/view/View;)V", - ) } // endregion @@ -106,20 +91,33 @@ val hidePlayerOverlayButtonsPatch = bytecodePatch( """ invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->getCastButtonOverrideV2(I)I move-result p1 - """, + """ ) + if (is_20_28_or_greater) { + arrayOf( + castButtonPlayerFeatureFlagFingerprint, + castButtonActionFeatureFlagFingerprint + ).forEach { fingerprint -> + fingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->getCastButtonOverrideV2(Z)Z" + ) + } + } + } + // endregion // region Hide captions button. subtitleButtonControllerFingerprint.method.apply { - // Due to previously applied patches, scanResult index cannot be used in this context val insertIndex = indexOfFirstInstructionOrThrow(Opcode.IGET_BOOLEAN) + 1 addInstruction( insertIndex, - "invoke-static {v0}, $EXTENSION_CLASS_DESCRIPTOR->hideCaptionsButton(Landroid/widget/ImageView;)V", + "invoke-static { v0 }, $EXTENSION_CLASS_DESCRIPTOR->hideCaptionsButton(Landroid/widget/ImageView;)V", ) } @@ -154,27 +152,21 @@ val hidePlayerOverlayButtonsPatch = bytecodePatch( // region Hide player control buttons background. - inflateControlsGroupLayoutStubFingerprint.method.apply { - val controlsButtonGroupLayoutStubResIdConstIndex = - indexOfFirstLiteralInstructionOrThrow(controlsButtonGroupLayoutStub) - val inflateControlsGroupLayoutStubIndex = - indexOfFirstInstruction(controlsButtonGroupLayoutStubResIdConstIndex) { - getReference()?.name == "inflate" - } + inflateControlsGroupLayoutStubFingerprint.let { + it.method.apply { + val insertIndex = it.instructionMatches.last().index + 1 + val freeRegister = findFreeRegister(insertIndex) - val freeRegister = findFreeRegister(inflateControlsGroupLayoutStubIndex) - val hidePlayerControlButtonsBackgroundDescriptor = - "$EXTENSION_CLASS_DESCRIPTOR->hidePlayerControlButtonsBackground(Landroid/view/View;)V" - - addInstructions( - inflateControlsGroupLayoutStubIndex + 1, - """ - # Move the inflated layout to a temporary register. - # The result of the inflate method is by default not moved to a register after the method is called. - move-result-object v$freeRegister - invoke-static { v$freeRegister }, $hidePlayerControlButtonsBackgroundDescriptor - """ - ) + addInstructions( + insertIndex, + """ + # Move the inflated layout to a temporary register. + # The result of the inflate method is by default not moved to a register after the method is called. + move-result-object v$freeRegister + invoke-static { v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->hidePlayerControlButtonsBackground(Landroid/view/View;)V + """ + ) + } } // endregion diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/formfactor/ChangeFormFactorPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/formfactor/ChangeFormFactorPatch.kt index 6e9672cf9..a0f14a06d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/formfactor/ChangeFormFactorPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/formfactor/ChangeFormFactorPatch.kt @@ -2,6 +2,8 @@ package app.revanced.patches.youtube.layout.formfactor import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.fieldAccess +import app.revanced.patcher.fingerprint import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch @@ -11,11 +13,8 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.navigation.hookNavigationButtonCreated import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionOrThrow -import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction -import com.android.tools.smali.dexlib2.iface.reference.FieldReference private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ChangeFormFactorPatch;" @@ -51,24 +50,33 @@ val changeFormFactorPatch = bytecodePatch( hookNavigationButtonCreated(EXTENSION_CLASS_DESCRIPTOR) - createPlayerRequestBodyWithModelFingerprint.method.apply { - val formFactorEnumClass = formFactorEnumConstructorFingerprint.originalClassDef.type - - val index = indexOfFirstInstructionOrThrow { - val reference = getReference() - opcode == Opcode.IGET && - reference?.definingClass == formFactorEnumClass && - reference.type == "I" - } - val register = getInstruction(index).registerA - - addInstructions( - index + 1, - """ - invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getFormFactor(I)I - move-result v$register - """ + val createPlayerRequestBodyWithModelFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("L") + parameters() + instructions( + fieldAccess(smali = "Landroid/os/Build;->MODEL:Ljava/lang/String;"), + fieldAccess( + definingClass = formFactorEnumConstructorFingerprint.originalClassDef.type, + type = "I", + maxAfter = 50 + ) ) } + + createPlayerRequestBodyWithModelFingerprint.let { + it.method.apply { + val index = it.instructionMatches.last().index + val register = getInstruction(index).registerA + + addInstructions( + index + 1, + """ + invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getFormFactor(I)I + move-result v$register + """ + ) + } + } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/formfactor/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/formfactor/Fingerprints.kt index d1f1535eb..6ffedaf77 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/formfactor/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/formfactor/Fingerprints.kt @@ -1,14 +1,9 @@ package app.revanced.patches.youtube.layout.formfactor 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.Opcode -import com.android.tools.smali.dexlib2.iface.Method -import com.android.tools.smali.dexlib2.iface.reference.FieldReference -internal val formFactorEnumConstructorFingerprint = fingerprint { +internal val formFactorEnumConstructorFingerprint by fingerprint { accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) strings( "UNKNOWN_FORM_FACTOR", @@ -17,33 +12,3 @@ internal val formFactorEnumConstructorFingerprint = fingerprint { "AUTOMOTIVE_FORM_FACTOR" ) } - -internal val createPlayerRequestBodyWithModelFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("L") - parameters() - opcodes(Opcode.OR_INT_LIT16) - custom { method, _ -> - method.indexOfModelInstruction() >= 0 && - method.indexOfReleaseInstruction() >= 0 - } -} - -private fun Method.indexOfModelInstruction() = - indexOfFirstInstruction { - val reference = getReference() - - reference?.definingClass == "Landroid/os/Build;" && - reference.name == "MODEL" && - reference.type == "Ljava/lang/String;" - } - -internal fun Method.indexOfReleaseInstruction(): Int = - indexOfFirstInstruction { - val reference = getReference() - - reference?.definingClass == "Landroid/os/Build${'$'}VERSION;" && - reference.name == "RELEASE" && - reference.type == "Ljava/lang/String;" - } - diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/Fingerprints.kt index 59d859e80..dfd8f3110 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/Fingerprints.kt @@ -2,9 +2,12 @@ package app.revanced.patches.youtube.layout.hide.endscreencards import app.revanced.patcher.fingerprint import app.revanced.util.literal +import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val layoutCircleFingerprint = fingerprint { +internal val layoutCircleFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + parameters() returns("Landroid/view/View;") opcodes( Opcode.CONST, @@ -16,7 +19,9 @@ internal val layoutCircleFingerprint = fingerprint { literal { layoutCircle } } -internal val layoutIconFingerprint = fingerprint { +internal val layoutIconFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + parameters() returns("Landroid/view/View;") opcodes( Opcode.INVOKE_VIRTUAL, @@ -27,7 +32,9 @@ internal val layoutIconFingerprint = fingerprint { literal { layoutIcon } } -internal val layoutVideoFingerprint = fingerprint { +internal val layoutVideoFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC) + parameters() returns("Landroid/view/View;") opcodes( Opcode.CONST, diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatch.kt index 458801631..fabf558d9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatch.kt @@ -6,9 +6,9 @@ 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.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen @@ -36,7 +36,7 @@ private val hideEndscreenCardsResourcePatch = resourcePatch { SwitchPreference("revanced_hide_endscreen_cards"), ) - fun idOf(name: String) = resourceMappings["layout", "endscreen_element_layout_$name"] + fun idOf(name: String) = getResourceId(ResourceType.LAYOUT, "endscreen_element_layout_$name") layoutCircle = idOf("circle") layoutIcon = idOf("icon") @@ -75,7 +75,7 @@ val hideEndscreenCardsPatch = bytecodePatch( layoutVideoFingerprint, ).forEach { fingerprint -> fingerprint.method.apply { - val insertIndex = fingerprint.patternMatch!!.endIndex + 1 + val insertIndex = fingerprint.instructionMatches.last().index + 1 val viewRegister = getInstruction(insertIndex - 1).registerA addInstruction( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/Fingerprints.kt index 887963e56..97641725f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/Fingerprints.kt @@ -7,19 +7,19 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal val autoNavConstructorFingerprint = fingerprint { +internal val autoNavConstructorFingerprint by fingerprint { returns("V") accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) strings("main_app_autonav") } -internal val autoNavStatusFingerprint = fingerprint { +internal val autoNavStatusFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() } -internal val removeOnLayoutChangeListenerFingerprint = fingerprint { +internal val removeOnLayoutChangeListenerFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatch.kt index db5115207..d5e16b126 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatch.kt @@ -48,7 +48,7 @@ val hideEndScreenSuggestedVideoPatch = bytecodePatch( ) removeOnLayoutChangeListenerFingerprint.let { - val endScreenMethod = navigate(it.originalMethod).to(it.patternMatch!!.endIndex).stop() + val endScreenMethod = navigate(it.originalMethod).to(it.instructionMatches.last().index).stop() endScreenMethod.apply { val autoNavStatusMethodName = autoNavStatusFingerprint.match( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/Fingerprints.kt index b61902087..fff4d8621 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.youtube.layout.hide.fullscreenambientmode import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal val setFullScreenBackgroundColorFingerprint = fingerprint { +internal val setFullScreenBackgroundColorFingerprint by fingerprint { returns("V") accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL) parameters("Z", "I", "I", "I", "I") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/Fingerprints.kt index e83689607..7b508b5e4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/Fingerprints.kt @@ -1,68 +1,60 @@ package app.revanced.patches.youtube.layout.hide.general +import app.revanced.patcher.checkCast import app.revanced.patcher.fingerprint +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patcher.string +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import app.revanced.patches.youtube.layout.searchbar.wideSearchbarLayoutFingerprint import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val hideShowMoreButtonFingerprint = fingerprint { - opcodes( - Opcode.CONST, - Opcode.CONST_4, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - ) - literal { expandButtonDownId } -} - /** - * 20.12+ + * 20.26+ */ -internal val parseElementFromBufferFingerprint = fingerprint { - parameters("L", "L", "[B", "L", "L") - opcodes( - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, +internal val hideShowMoreButtonFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL, AccessFlags.SYNTHETIC) + returns("V") + parameters("L", "Ljava/lang/Object;") + instructions( + resourceLiteral(ResourceType.LAYOUT, "expand_button_down"), + methodCall(smali = "Landroid/view/LayoutInflater;->inflate(ILandroid/view/ViewGroup;Z)Landroid/view/View;"), + opcode(Opcode.MOVE_RESULT_OBJECT, 0) ) - strings("Failed to parse Element") // String is a partial match. } -/** - * 20.07+ - */ -internal val parseElementFromBufferLegacy2007Fingerprint = fingerprint { - parameters("L", "L", "[B", "L", "L") - opcodes( - Opcode.IGET_OBJECT, - Opcode.IGET_BOOLEAN, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, +internal val hideShowMoreLegacyButtonFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) + instructions( + resourceLiteral(ResourceType.LAYOUT, "expand_button_down"), + methodCall(smali = "Landroid/view/View;->inflate(Landroid/content/Context;ILandroid/view/ViewGroup;)Landroid/view/View;"), + opcode(Opcode.MOVE_RESULT_OBJECT) ) - strings("Failed to parse Element") // String is a partial match. } -/** - * 19.01 - 20.06 - */ -internal val parseElementFromBufferLegacy1901Fingerprint = fingerprint { +internal val parseElementFromBufferFingerprint by fingerprint { parameters("L", "L", "[B", "L", "L") - opcodes( - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, + instructions( + opcode(Opcode.IGET_OBJECT), + // IGET_BOOLEAN // 20.07+ + opcode(Opcode.INVOKE_INTERFACE, maxAfter = 1), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0), + string("Failed to parse Element", partialMatch = true) ) - strings("Failed to parse Element") // String is a partial match. } -internal val playerOverlayFingerprint = fingerprint { +internal val playerOverlayFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") - strings("player_overlay_in_video_programming") + instructions( + string("player_overlay_in_video_programming") + ) } -internal val showWatermarkFingerprint = fingerprint { +internal val showWatermarkFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L", "L") @@ -71,14 +63,16 @@ internal val showWatermarkFingerprint = fingerprint { /** * Matches same method as [wideSearchbarLayoutFingerprint]. */ -internal val yoodlesImageViewFingerprint = fingerprint { +internal val yoodlesImageViewFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Landroid/view/View;") parameters("L", "L") - literal { youTubeLogo } + instructions( + resourceLiteral(ResourceType.ID, "youtube_logo") + ) } -internal val crowdfundingBoxFingerprint = fingerprint { +internal val crowdfundingBoxFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) opcodes( Opcode.INVOKE_VIRTUAL, @@ -88,7 +82,7 @@ internal val crowdfundingBoxFingerprint = fingerprint { literal { crowdfundingBoxId } } -internal val albumCardsFingerprint = fingerprint { +internal val albumCardsFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) opcodes( Opcode.MOVE_RESULT_OBJECT, @@ -101,9 +95,8 @@ internal val albumCardsFingerprint = fingerprint { literal { albumCardId } } -internal val filterBarHeightFingerprint = fingerprint { +internal val filterBarHeightFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") opcodes( Opcode.CONST, Opcode.INVOKE_VIRTUAL, @@ -113,9 +106,8 @@ internal val filterBarHeightFingerprint = fingerprint { literal { filterBarHeightId } } -internal val relatedChipCloudFingerprint = fingerprint { +internal val relatedChipCloudFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") opcodes( Opcode.CONST, Opcode.INVOKE_VIRTUAL, @@ -124,9 +116,8 @@ internal val relatedChipCloudFingerprint = fingerprint { literal { relatedChipCloudMarginId } } -internal val searchResultsChipBarFingerprint = fingerprint { +internal val searchResultsChipBarFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") opcodes( Opcode.CONST, Opcode.INVOKE_VIRTUAL, @@ -137,13 +128,13 @@ internal val searchResultsChipBarFingerprint = fingerprint { literal { barContainerHeightId } } -internal val showFloatingMicrophoneButtonFingerprint = fingerprint { +internal val showFloatingMicrophoneButtonFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters() - opcodes( - Opcode.IGET_BOOLEAN, - Opcode.IF_EQZ, + instructions( + resourceLiteral(ResourceType.ID, "fab"), + checkCast("/FloatingActionButton;", maxAfter = 10), + opcode(Opcode.IGET_BOOLEAN, maxAfter = 10) ) - literal { fabButtonId } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt index 4c9bac27c..750f1e682 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt @@ -14,22 +14,24 @@ import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.util.smali.ExternalLabel 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.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings -import app.revanced.patches.shared.misc.settings.preference.* +import app.revanced.patches.shared.misc.settings.preference.InputType +import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.patches.shared.misc.settings.preference.TextPreference import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch -import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater -import app.revanced.patches.youtube.misc.playservice.is_20_09_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_26_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.util.findFreeRegister import app.revanced.util.findInstructionIndicesReversedOrThrow import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.indexOfFirstLiteralInstructionOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @@ -37,66 +39,45 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference -var expandButtonDownId = -1L +internal var albumCardId = -1L private set -var albumCardId = -1L +internal var crowdfundingBoxId = -1L private set -var crowdfundingBoxId = -1L +internal var filterBarHeightId = -1L private set -var youTubeLogo = -1L +internal var relatedChipCloudMarginId = -1L private set -var filterBarHeightId = -1L - private set -var relatedChipCloudMarginId = -1L - private set -var barContainerHeightId = -1L - private set -var fabButtonId = -1L +internal var barContainerHeightId = -1L private set private val hideLayoutComponentsResourcePatch = resourcePatch { dependsOn(resourceMappingPatch) execute { - expandButtonDownId = resourceMappings[ - "layout", - "expand_button_down", - ] - - albumCardId = resourceMappings[ - "layout", + albumCardId = getResourceId( + ResourceType.LAYOUT, "album_card", - ] + ) - crowdfundingBoxId = resourceMappings[ - "layout", + crowdfundingBoxId = getResourceId( + ResourceType.LAYOUT, "donation_companion", - ] + ) - youTubeLogo = resourceMappings[ - "id", - "youtube_logo", - ] - - relatedChipCloudMarginId = resourceMappings[ - "layout", + relatedChipCloudMarginId = getResourceId( + ResourceType.LAYOUT, "related_chip_cloud_reduced_margins", - ] + ) - filterBarHeightId = resourceMappings[ - "dimen", + filterBarHeightId = getResourceId( + ResourceType.DIMEN, "filter_bar_height", - ] + ) - barContainerHeightId = resourceMappings[ - "dimen", + barContainerHeightId = getResourceId( + ResourceType.DIMEN, "bar_container_height", - ] - - fabButtonId = resourceMappings[ - "id", - "fab", - ] + ) } } @@ -122,6 +103,8 @@ val hideLayoutComponentsPatch = bytecodePatch( addResourcesPatch, hideLayoutComponentsResourcePatch, navigationBarHookPatch, + versionCheckPatch, + resourceMappingPatch ) compatibleWith( @@ -257,32 +240,29 @@ val hideLayoutComponentsPatch = bytecodePatch( // region Mix playlists - (if (is_20_09_or_greater) parseElementFromBufferFingerprint - else if (is_20_07_or_greater) parseElementFromBufferLegacy2007Fingerprint - else parseElementFromBufferLegacy1901Fingerprint).let { - it.method.apply { - val byteArrayParameter = "p3" - val startIndex = it.patternMatch!!.startIndex - val conversionContextRegister = getInstruction(startIndex).registerA - val returnEmptyComponentInstruction = instructions.last { it.opcode == Opcode.INVOKE_STATIC } - val returnEmptyComponentRegister = (returnEmptyComponentInstruction as FiveRegisterInstruction).registerC - val insertIndex = startIndex + 1 - val freeRegister = findFreeRegister(insertIndex, conversionContextRegister, returnEmptyComponentRegister) + parseElementFromBufferFingerprint.method.apply { + val startIndex = parseElementFromBufferFingerprint.instructionMatches.first().index + val insertIndex = startIndex + 1 - addInstructionsWithLabels( - insertIndex, - """ - invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z - move-result v$freeRegister - if-eqz v$freeRegister, :show - move-object v$returnEmptyComponentRegister, p1 # Required for 19.47 - goto :return_empty_component - :show - nop - """, - ExternalLabel("return_empty_component", returnEmptyComponentInstruction), - ) - } + val byteArrayParameter = "p3" + val conversionContextRegister = getInstruction(startIndex).registerA + val returnEmptyComponentInstruction = instructions.last { it.opcode == Opcode.INVOKE_STATIC } + val returnEmptyComponentRegister = (returnEmptyComponentInstruction as FiveRegisterInstruction).registerC + val freeRegister = findFreeRegister(insertIndex, conversionContextRegister, returnEmptyComponentRegister) + + addInstructionsWithLabels( + insertIndex, + """ + invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z + move-result v$freeRegister + if-eqz v$freeRegister, :show + move-object v$returnEmptyComponentRegister, p1 # Required for 19.47 + goto :return_empty_component + :show + nop + """, + ExternalLabel("return_empty_component", returnEmptyComponentInstruction), + ) } // endregion @@ -308,16 +288,18 @@ val hideLayoutComponentsPatch = bytecodePatch( // region Show more button - hideShowMoreButtonFingerprint.method.apply { - val moveRegisterIndex = hideShowMoreButtonFingerprint.patternMatch!!.endIndex - val viewRegister = getInstruction(moveRegisterIndex).registerA + (if (is_20_26_or_greater) hideShowMoreButtonFingerprint else hideShowMoreLegacyButtonFingerprint).let { + it.method.apply { + val moveRegisterIndex = it.instructionMatches.last().index + val viewRegister = getInstruction(moveRegisterIndex).registerA - val insertIndex = moveRegisterIndex + 1 - addInstruction( - insertIndex, - "invoke-static { v$viewRegister }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR" + - "->hideShowMoreButton(Landroid/view/View;)V", - ) + val insertIndex = moveRegisterIndex + 1 + addInstruction( + insertIndex, + "invoke-static { v$viewRegister }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR" + + "->hideShowMoreButton(Landroid/view/View;)V", + ) + } } // endregion @@ -325,7 +307,7 @@ val hideLayoutComponentsPatch = bytecodePatch( // region crowdfunding box crowdfundingBoxFingerprint.let { it.method.apply { - val insertIndex = it.patternMatch!!.endIndex + val insertIndex = it.instructionMatches.last().index val objectRegister = getInstruction(insertIndex).registerA addInstruction( @@ -342,7 +324,7 @@ val hideLayoutComponentsPatch = bytecodePatch( albumCardsFingerprint.let { it.method.apply { - val checkCastAnchorIndex = it.patternMatch!!.endIndex + val checkCastAnchorIndex = it.instructionMatches.last().index val insertIndex = checkCastAnchorIndex + 1 val register = getInstruction(checkCastAnchorIndex).registerA @@ -358,18 +340,19 @@ val hideLayoutComponentsPatch = bytecodePatch( // region hide floating microphone - showFloatingMicrophoneButtonFingerprint.method.apply { - val literalIndex = indexOfFirstLiteralInstructionOrThrow(fabButtonId) - val booleanIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.IGET_BOOLEAN) - val register = getInstruction(booleanIndex).registerA + showFloatingMicrophoneButtonFingerprint.let { + it.method.apply { + val index = it.instructionMatches.last().index + val register = getInstruction(index).registerA - addInstructions( - booleanIndex + 1, - """ - invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideFloatingMicrophoneButton(Z)Z - move-result v$register - """ - ) + addInstructions( + index + 1, + """ + invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideFloatingMicrophoneButton(Z)Z + move-result v$register + """, + ) + } } // endregion @@ -408,11 +391,9 @@ val hideLayoutComponentsPatch = bytecodePatch( hookRegisterOffset: Int = 0, instructions: (Int) -> String, ) = method.apply { - val endIndex = patternMatch!!.endIndex - + val endIndex = instructionMatches.last().index val insertIndex = endIndex + insertIndexOffset - val register = - getInstruction(endIndex + hookRegisterOffset).registerA + val register = getInstruction(endIndex + hookRegisterOffset).registerA addInstructions(insertIndex, instructions(register)) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/Fingerprints.kt index 5088472a1..6b1b09d58 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/Fingerprints.kt @@ -1,24 +1,29 @@ package app.revanced.patches.youtube.layout.hide.infocards import app.revanced.patcher.fingerprint +import app.revanced.patcher.string import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val infocardsIncognitoFingerprint = fingerprint { +internal val infocardsIncognitoFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/Boolean;") parameters("L", "J") - strings("vibrator") + instructions( + string("vibrator") + ) } -internal val infocardsIncognitoParentFingerprint = fingerprint { +internal val infocardsIncognitoParentFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/String;") - strings("player_overlay_info_card_teaser") + instructions( + string("player_overlay_info_card_teaser") + ) } -internal val infocardsMethodCallFingerprint = fingerprint { +internal val infocardsMethodCallFingerprint by fingerprint { opcodes( Opcode.INVOKE_VIRTUAL, Opcode.IGET_OBJECT, diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt index cac5c169b..a7d9a73b6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt @@ -8,9 +8,9 @@ import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.util.smali.ExternalLabel 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.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter @@ -25,22 +25,13 @@ internal var drawerResourceId = -1L private set private val hideInfocardsResourcePatch = resourcePatch { - dependsOn( - settingsPatch, - resourceMappingPatch, - addResourcesPatch, + dependsOn(resourceMappingPatch ) execute { - addResources("youtube", "layout.hide.infocards.hideInfocardsResourcePatch") - - PreferenceScreen.PLAYER.addPreferences( - SwitchPreference("revanced_hide_info_cards"), - ) - - drawerResourceId = resourceMappings[ - "id", + drawerResourceId = getResourceId( + ResourceType.ID, "info_cards_drawer_header", - ] + ) } } @@ -53,6 +44,8 @@ val hideInfoCardsPatch = bytecodePatch( sharedExtensionPatch, lithoFilterPatch, hideInfocardsResourcePatch, + settingsPatch, + addResourcesPatch, ) compatibleWith( @@ -67,6 +60,13 @@ val hideInfoCardsPatch = bytecodePatch( ) execute { + addResources("youtube", "layout.hide.infocards.hideInfocardsResourcePatch") + + PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_hide_info_cards"), + ) + + // Edit: This old non litho code may be obsolete and no longer used by any supported versions. infocardsIncognitoFingerprint.match(infocardsIncognitoParentFingerprint.originalClassDef).method.apply { val invokeInstructionIndex = implementation!!.instructions.indexOfFirst { it.opcode.ordinal == Opcode.INVOKE_VIRTUAL.ordinal && @@ -80,23 +80,26 @@ val hideInfoCardsPatch = bytecodePatch( ) } - val hideInfoCardsCallMethod = infocardsMethodCallFingerprint.method + // Edit: This old non litho code may be obsolete and no longer used by any supported versions. + infocardsMethodCallFingerprint.let { + val invokeInterfaceIndex = it.instructionMatches.last().index + it.method.apply { + val register = implementation!!.registerCount - 1 - val invokeInterfaceIndex = infocardsMethodCallFingerprint.patternMatch!!.endIndex - val toggleRegister = infocardsMethodCallFingerprint.method.implementation!!.registerCount - 1 - - hideInfoCardsCallMethod.addInstructionsWithLabels( - invokeInterfaceIndex, - """ - invoke-static {}, Lapp/revanced/extension/youtube/patches/HideInfoCardsPatch;->hideInfoCardsMethodCall()Z - move-result v$toggleRegister - if-nez v$toggleRegister, :hide_info_cards - """, - ExternalLabel( - "hide_info_cards", - hideInfoCardsCallMethod.getInstruction(invokeInterfaceIndex + 1), - ), - ) + addInstructionsWithLabels( + invokeInterfaceIndex, + """ + invoke-static {}, Lapp/revanced/extension/youtube/patches/HideInfoCardsPatch;->hideInfoCardsMethodCall()Z + move-result v$register + if-nez v$register, :hide_info_cards + """, + ExternalLabel( + "hide_info_cards", + getInstruction(invokeInterfaceIndex + 1), + ) + ) + } + } // Info cards can also appear as Litho components. val filterClassDescriptor = "Lapp/revanced/extension/youtube/patches/components/HideInfoCardsFilter;" diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/relatedvideooverlay/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/relatedvideooverlay/Fingerprints.kt index 0ca129863..0db333809 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/relatedvideooverlay/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/relatedvideooverlay/Fingerprints.kt @@ -1,14 +1,17 @@ package app.revanced.patches.youtube.layout.hide.relatedvideooverlay import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral -internal val relatedEndScreenResultsParentFingerprint = fingerprint { +internal val relatedEndScreenResultsParentFingerprint by fingerprint { returns("V") - literal{ appRelatedEndScreenResults } + instructions( + resourceLiteral(ResourceType.LAYOUT, "app_related_endscreen_results") + ) } -internal val relatedEndScreenResultsFingerprint = fingerprint { +internal val relatedEndScreenResultsFingerprint by fingerprint { returns("V") parameters( "I", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/relatedvideooverlay/HideRelatedVideoOverlayPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/relatedvideooverlay/HideRelatedVideoOverlayPatch.kt index fa8fa9f04..9eaef0254 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/relatedvideooverlay/HideRelatedVideoOverlayPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/relatedvideooverlay/HideRelatedVideoOverlayPatch.kt @@ -3,33 +3,14 @@ package app.revanced.patches.youtube.layout.hide.relatedvideooverlay import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patcher.patch.resourcePatch +import app.revanced.patcher.util.smali.ExternalLabel 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.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.patcher.util.smali.ExternalLabel - -internal var appRelatedEndScreenResults = -1L - private set - -private val hideRelatedVideoOverlayResourcePatch = resourcePatch { - dependsOn( - resourceMappingPatch, - ) - - execute { - appRelatedEndScreenResults = resourceMappings[ - "layout", - "app_related_endscreen_results", - ] - } -} private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/HideRelatedVideoOverlayPatch;" @@ -43,7 +24,7 @@ val hideRelatedVideoOverlayPatch = bytecodePatch( settingsPatch, sharedExtensionPatch, addResourcesPatch, - hideRelatedVideoOverlayResourcePatch, + resourceMappingPatch, ) compatibleWith( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt index b81cab1cb..cf2660963 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt @@ -47,27 +47,27 @@ val disableRollingNumberAnimationPatch = bytecodePatch( // Animations are disabled by preventing an Image from being applied to the text span, // which prevents the animations from appearing. + rollingNumberTextViewAnimationUpdateFingerprint.let { + val blockStartIndex = it.instructionMatches.first().index + val blockEndIndex = it.instructionMatches.last().index + 1 + it.method.apply { + val freeRegister = getInstruction(blockStartIndex).registerA - val patternMatch = rollingNumberTextViewAnimationUpdateFingerprint.patternMatch!! - val blockStartIndex = patternMatch.startIndex - val blockEndIndex = patternMatch.endIndex + 1 - rollingNumberTextViewAnimationUpdateFingerprint.method.apply { - val freeRegister = getInstruction(blockStartIndex).registerA + // ReturnYouTubeDislike also makes changes to this same method, + // and must add control flow label to a noop instruction to + // ensure RYD patch adds its changes after the control flow label. + addInstructions(blockEndIndex, "nop") - // ReturnYouTubeDislike also makes changes to this same method, - // and must add control flow label to a noop instruction to - // ensure RYD patch adds its changes after the control flow label. - addInstructions(blockEndIndex, "nop") - - addInstructionsWithLabels( - blockStartIndex, - """ + addInstructionsWithLabels( + blockStartIndex, + """ invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->disableRollingNumberAnimations()Z move-result v$freeRegister if-nez v$freeRegister, :disable_animations """, - ExternalLabel("disable_animations", getInstruction(blockEndIndex)), - ) + ExternalLabel("disable_animations", getInstruction(blockEndIndex)), + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatch.kt deleted file mode 100644 index edf7390ce..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatch.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.seekbar - -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.youtube.interaction.seekbar.hideSeekbarPatch - -@Deprecated("Patch was moved to app.revanced.patches.youtube.interaction.seekbar") -val hideSeekbarPatch = bytecodePatch { - dependsOn( - hideSeekbarPatch - ) -} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/Fingerprints.kt index cc883425b..803090f59 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/Fingerprints.kt @@ -1,11 +1,16 @@ package app.revanced.patches.youtube.layout.hide.shorts import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patcher.string +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val legacyRenderBottomNavigationBarParentFingerprint = fingerprint { +internal val legacyRenderBottomNavigationBarParentFingerprint by fingerprint { parameters( "I", "I", @@ -14,18 +19,24 @@ internal val legacyRenderBottomNavigationBarParentFingerprint = fingerprint { "J", "L", ) - strings("aa") + instructions( + string("aa") + ) } -internal val shortsBottomBarContainerFingerprint = fingerprint { +internal val shortsBottomBarContainerFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Landroid/view/View;", "Landroid/os/Bundle;") - strings("r_pfvc") - literal { bottomBarContainer } + instructions( + string("r_pfvc"), + resourceLiteral(ResourceType.ID, "bottom_bar_container"), + methodCall(name = "getHeight"), + opcode(Opcode.MOVE_RESULT) + ) } -internal val renderBottomNavigationBarFingerprint = fingerprint { +internal val renderBottomNavigationBarFingerprint by fingerprint { returns("V") parameters("Ljava/lang/String;") opcodes( @@ -46,7 +57,7 @@ internal val renderBottomNavigationBarFingerprint = fingerprint { * Identical to [legacyRenderBottomNavigationBarParentFingerprint] * except this has an extra parameter. */ -internal val renderBottomNavigationBarParentFingerprint = fingerprint { +internal val renderBottomNavigationBarParentFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters( "I", @@ -57,10 +68,12 @@ internal val renderBottomNavigationBarParentFingerprint = fingerprint { "Ljava/lang/String;", "L", ) - strings("aa") + instructions( + string("aa") + ) } -internal val setPivotBarVisibilityFingerprint = fingerprint { +internal val setPivotBarVisibilityFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returns("V") parameters("Z") @@ -70,25 +83,27 @@ internal val setPivotBarVisibilityFingerprint = fingerprint { ) } -internal val setPivotBarVisibilityParentFingerprint = fingerprint { +internal val setPivotBarVisibilityParentFingerprint by fingerprint { parameters("Z") - strings("FEnotifications_inbox") + instructions( + string("FEnotifications_inbox") + ) } -internal val shortsExperimentalPlayerFeatureFlagFingerprint = fingerprint { +internal val shortsExperimentalPlayerFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() - literal { - 45677719L - } + instructions( + literal(45677719L) + ) } -internal val renderNextUIFeatureFlagFingerprint = fingerprint { +internal val renderNextUIFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() - literal { - 45649743L - } + instructions( + literal(45649743L) + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt index 1faab015e..ea979a07d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt @@ -8,9 +8,9 @@ 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.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch @@ -19,6 +19,7 @@ import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch import app.revanced.patches.youtube.misc.playservice.is_19_41_or_greater import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_22_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch @@ -26,16 +27,10 @@ import app.revanced.util.findElementByAttributeValueOrThrow import app.revanced.util.forEachLiteralValueInstruction import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.indexOfFirstLiteralInstruction import app.revanced.util.returnLate import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal var bottomBarContainer = -1L - private set -internal var reelPlayerRightPivotV2Size = -1L - private set - internal val hideShortsAppShortcutOption = booleanOption( key = "hideShortsAppShortcut", default = false, @@ -64,6 +59,62 @@ private val hideShortsComponentsResourcePatch = resourcePatch { addResources("youtube", "layout.hide.shorts.hideShortsComponentsResourcePatch") + val preferences = mutableSetOf( + // Shorts player components. + // Ideally each group should be ordered similar to how they appear in the UI + + // Vertical row of buttons on right side of the screen. + SwitchPreference("revanced_hide_shorts_like_fountain"), + SwitchPreference("revanced_hide_shorts_like_button"), + SwitchPreference("revanced_hide_shorts_dislike_button"), + ) + + if (!is_20_22_or_greater) { + // FIXME: The buffer is very different for 20.22+ and these current cannot be hidden. + preferences.addAll( + listOf( + SwitchPreference("revanced_hide_shorts_comments_button"), + SwitchPreference("revanced_hide_shorts_share_button"), + SwitchPreference("revanced_hide_shorts_remix_button"), + SwitchPreference("revanced_hide_shorts_sound_button") + ) + ) + } + + preferences.addAll( + listOf( + // Upper and middle area of the player. + SwitchPreference("revanced_hide_shorts_join_button"), + SwitchPreference("revanced_hide_shorts_subscribe_button"), + SwitchPreference("revanced_hide_shorts_paused_overlay_buttons"), + + // Suggested actions. + SwitchPreference("revanced_hide_shorts_preview_comment"), + SwitchPreference("revanced_hide_shorts_save_sound_button"), + SwitchPreference("revanced_hide_shorts_use_sound_button"), + SwitchPreference("revanced_hide_shorts_use_template_button"), + SwitchPreference("revanced_hide_shorts_upcoming_button"), + SwitchPreference("revanced_hide_shorts_effect_button"), + SwitchPreference("revanced_hide_shorts_green_screen_button"), + SwitchPreference("revanced_hide_shorts_hashtag_button"), + SwitchPreference("revanced_hide_shorts_new_posts_button"), + SwitchPreference("revanced_hide_shorts_shop_button"), + SwitchPreference("revanced_hide_shorts_tagged_products"), + SwitchPreference("revanced_hide_shorts_search_suggestions"), + SwitchPreference("revanced_hide_shorts_super_thanks_button"), + SwitchPreference("revanced_hide_shorts_stickers"), + + // Bottom of the screen. + SwitchPreference("revanced_hide_shorts_location_label"), + SwitchPreference("revanced_hide_shorts_channel_bar"), + SwitchPreference("revanced_hide_shorts_info_panel"), + SwitchPreference("revanced_hide_shorts_full_video_link_label"), + SwitchPreference("revanced_hide_shorts_video_title"), + SwitchPreference("revanced_hide_shorts_sound_metadata_label"), + SwitchPreference("revanced_hide_shorts_navigation_bar"), + ) + ) + PreferenceScreen.SHORTS.addPreferences( SwitchPreference("revanced_hide_shorts_home"), SwitchPreference("revanced_hide_shorts_search"), @@ -73,50 +124,8 @@ private val hideShortsComponentsResourcePatch = resourcePatch { PreferenceScreenPreference( key = "revanced_shorts_player_screen", sorting = PreferenceScreenPreference.Sorting.UNSORTED, - preferences = setOf( - // Shorts player components. - // Ideally each group should be ordered similar to how they appear in the UI - - // Vertical row of buttons on right side of the screen. - SwitchPreference("revanced_hide_shorts_like_fountain"), - SwitchPreference("revanced_hide_shorts_like_button"), - SwitchPreference("revanced_hide_shorts_dislike_button"), - SwitchPreference("revanced_hide_shorts_comments_button"), - SwitchPreference("revanced_hide_shorts_share_button"), - SwitchPreference("revanced_hide_shorts_remix_button"), - SwitchPreference("revanced_hide_shorts_sound_button"), - - // Upper and middle area of the player. - SwitchPreference("revanced_hide_shorts_join_button"), - SwitchPreference("revanced_hide_shorts_subscribe_button"), - SwitchPreference("revanced_hide_shorts_paused_overlay_buttons"), - - // Suggested actions. - SwitchPreference("revanced_hide_shorts_preview_comment"), - SwitchPreference("revanced_hide_shorts_save_sound_button"), - SwitchPreference("revanced_hide_shorts_use_sound_button"), - SwitchPreference("revanced_hide_shorts_use_template_button"), - SwitchPreference("revanced_hide_shorts_upcoming_button"), - SwitchPreference("revanced_hide_shorts_effect_button"), - SwitchPreference("revanced_hide_shorts_green_screen_button"), - SwitchPreference("revanced_hide_shorts_hashtag_button"), - SwitchPreference("revanced_hide_shorts_new_posts_button"), - SwitchPreference("revanced_hide_shorts_shop_button"), - SwitchPreference("revanced_hide_shorts_tagged_products"), - SwitchPreference("revanced_hide_shorts_search_suggestions"), - SwitchPreference("revanced_hide_shorts_super_thanks_button"), - SwitchPreference("revanced_hide_shorts_stickers"), - - // Bottom of the screen. - SwitchPreference("revanced_hide_shorts_location_label"), - SwitchPreference("revanced_hide_shorts_channel_bar"), - SwitchPreference("revanced_hide_shorts_info_panel"), - SwitchPreference("revanced_hide_shorts_full_video_link_label"), - SwitchPreference("revanced_hide_shorts_video_title"), - SwitchPreference("revanced_hide_shorts_sound_metadata_label"), - SwitchPreference("revanced_hide_shorts_navigation_bar"), - ), - ), + preferences = preferences, + ) ) // Verify the file has the expected node, even if the patch option is off. @@ -141,16 +150,6 @@ private val hideShortsComponentsResourcePatch = resourcePatch { shortsItem.parentNode.removeChild(shortsItem) } } - - bottomBarContainer = resourceMappings[ - "id", - "bottom_bar_container", - ] - - reelPlayerRightPivotV2Size = resourceMappings[ - "dimen", - "reel_player_right_pivot_v2_size", - ] } } @@ -188,7 +187,7 @@ val hideShortsComponentsPatch = bytecodePatch( addLithoFilter(FILTER_CLASS_DESCRIPTOR) forEachLiteralValueInstruction( - reelPlayerRightPivotV2Size, + getResourceId(ResourceType.DIMEN, "reel_player_right_pivot_v2_size") ) { literalInstructionIndex -> val targetIndex = indexOfFirstInstructionOrThrow(literalInstructionIndex) { getReference()?.name == "getDimensionPixelSize" @@ -214,7 +213,7 @@ val hideShortsComponentsPatch = bytecodePatch( setPivotBarVisibilityParentFingerprint.originalClassDef, ).let { result -> result.method.apply { - val insertIndex = result.patternMatch!!.endIndex + val insertIndex = result.instructionMatches.last().index val viewRegister = getInstruction(insertIndex - 1).registerA addInstruction( insertIndex, @@ -237,26 +236,24 @@ val hideShortsComponentsPatch = bytecodePatch( ) // Hide the bottom bar container of the Shorts player. - shortsBottomBarContainerFingerprint.method.apply { - val resourceIndex = indexOfFirstLiteralInstruction(bottomBarContainer) + shortsBottomBarContainerFingerprint.let { + it.method.apply { + val targetIndex = it.instructionMatches.last().index + val heightRegister = getInstruction(targetIndex).registerA - val targetIndex = indexOfFirstInstructionOrThrow(resourceIndex) { - getReference()?.name == "getHeight" - } + 1 - - val heightRegister = getInstruction(targetIndex).registerA - - addInstructions( - targetIndex + 1, - """ - invoke-static { v$heightRegister }, $FILTER_CLASS_DESCRIPTOR->getNavigationBarHeight(I)I - move-result v$heightRegister - """ - ) + addInstructions( + targetIndex + 1, + """ + invoke-static { v$heightRegister }, $FILTER_CLASS_DESCRIPTOR->getNavigationBarHeight(I)I + move-result v$heightRegister + """ + ) + } } // endregion + // region Disable experimental Shorts flags. // Flags might be present in earlier targets, but they are not found in 19.47.53. diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/signintotvpopup/DisableSignInToTvPatchPopup.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/signintotvpopup/DisableSignInToTvPatchPopup.kt index 1a591c315..da5fbce3f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/signintotvpopup/DisableSignInToTvPatchPopup.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/signintotvpopup/DisableSignInToTvPatchPopup.kt @@ -4,17 +4,12 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith import app.revanced.patcher.patch.bytecodePatch 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.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch -internal var mdx_seamless_tv_sign_in_drawer_fragment_title_id = -1L - private set - private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/DisableSignInToTvPopupPatch;" @@ -47,11 +42,6 @@ val disableSignInToTvPopupPatch = bytecodePatch( SwitchPreference("revanced_disable_signin_to_tv_popup"), ) - mdx_seamless_tv_sign_in_drawer_fragment_title_id = resourceMappings[ - "string", - "mdx_seamless_tv_sign_in_drawer_fragment_title", - ] - signInToTvPopupFingerprint.method.addInstructionsWithLabels( 0, """ diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/signintotvpopup/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/signintotvpopup/Fingerprints.kt index c79d4ed26..ad973642c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/signintotvpopup/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/signintotvpopup/Fingerprints.kt @@ -1,12 +1,16 @@ package app.revanced.patches.youtube.layout.hide.signintotvpopup import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral -internal val signInToTvPopupFingerprint = fingerprint { +internal val signInToTvPopupFingerprint by fingerprint { returns("Z") parameters("Ljava/lang/String;", "Z", "L") - literal { - mdx_seamless_tv_sign_in_drawer_fragment_title_id - } + instructions( + resourceLiteral( + ResourceType.STRING, + "mdx_seamless_tv_sign_in_drawer_fragment_title" + ) + ) } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatch.kt deleted file mode 100644 index 388aee7ad..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatch.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.suggestedvideoendscreen - -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.youtube.layout.hide.endscreensuggestion.hideEndScreenSuggestedVideoPatch - -@Deprecated("Use 'Hide suggested video end screen' instead.") -val disableSuggestedVideoEndScreenPatch = bytecodePatch { - dependsOn(hideEndScreenSuggestedVideoPatch) -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/Fingerprints.kt index 1f1876dc3..4e4526f7f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/Fingerprints.kt @@ -1,16 +1,32 @@ package app.revanced.patches.youtube.layout.hide.time +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val timeCounterFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) +internal val timeCounterFingerprint by fingerprint { returns("V") + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters() - opcodes( - Opcode.SUB_LONG_2ADDR, - Opcode.IGET_WIDE, - Opcode.SUB_LONG_2ADDR + instructions( + opcode(Opcode.SUB_LONG_2ADDR), + methodCall( + opcode = Opcode.INVOKE_STATIC, + returnType = "Ljava/lang/CharSequence;", + maxAfter = 0 + ), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0), + fieldAccess(opcode = Opcode.IGET_WIDE, type = "J", maxAfter = 0), + fieldAccess(opcode = Opcode.IGET_WIDE, type = "J", maxAfter = 0), + opcode(Opcode.SUB_LONG_2ADDR, maxAfter = 0), + + methodCall( + opcode = Opcode.INVOKE_STATIC, + returnType = "Ljava/lang/CharSequence;", + maxAfter = 5 + ) ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt index 6d9bfb567..ca54de32b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt @@ -9,6 +9,8 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch +private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/HideTimestampPatch;" + val hideTimestampPatch = bytecodePatch( name = "Hide timestamp", description = "Adds an option to hide the timestamp in the bottom left of the video player.", @@ -40,13 +42,13 @@ val hideTimestampPatch = bytecodePatch( timeCounterFingerprint.method.addInstructionsWithLabels( 0, """ - invoke-static { }, Lapp/revanced/extension/youtube/patches/HideTimestampPatch;->hideTimestamp()Z + invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideTimestamp()Z move-result v0 if-eqz v0, :hide_time return-void :hide_time nop - """, + """ ) } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/Fingerprints.kt index 8c139aee4..7455cc373 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/Fingerprints.kt @@ -2,39 +2,17 @@ package app.revanced.patches.youtube.layout.miniplayer +import app.revanced.patcher.checkCast import app.revanced.patcher.fingerprint -import app.revanced.util.containsLiteralInstruction -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patcher.string +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val miniplayerDimensionsCalculatorParentFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("V") - parameters("L") - literal { floatyBarButtonTopMargin } -} - -/** - * Matches using the class found in [miniplayerModernViewParentFingerprint]. - */ -internal val miniplayerModernAddViewListenerFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("V") - parameters("Landroid/view/View;") -} - -/** - * Matches using the class found in [miniplayerModernViewParentFingerprint]. - */ - -internal val miniplayerModernCloseButtonFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("L") - parameters() - literal { modernMiniplayerClose } -} - internal const val MINIPLAYER_MODERN_FEATURE_KEY = 45622882L // In later targets this feature flag does nothing and is dead code. internal const val MINIPLAYER_MODERN_FEATURE_LEGACY_KEY = 45630429L @@ -44,104 +22,159 @@ internal const val MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY = 45658112L internal const val MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY = 45652224L internal const val MINIPLAYER_INITIAL_SIZE_FEATURE_KEY = 45640023L internal const val MINIPLAYER_DISABLED_FEATURE_KEY = 45657015L +internal const val MINIPLAYER_ANIMATED_EXPAND_FEATURE_KEY = 45644360L -internal val miniplayerModernConstructorFingerprint = fingerprint { +internal val miniplayerModernConstructorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - parameters("L") - literal { 45623000L } + instructions( + literal(45623000L) // Magic number found in the constructor. + ) } -internal val miniplayerOnCloseHandlerFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("Z") - literal { MINIPLAYER_DISABLED_FEATURE_KEY } -} - -/** - * Matches using the class found in [miniplayerModernViewParentFingerprint]. - */ -internal val miniplayerModernExpandButtonFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("L") - parameters() - literal { modernMiniplayerExpand } -} - -/** - * Matches using the class found in [miniplayerModernViewParentFingerprint]. - */ -internal val miniplayerModernExpandCloseDrawablesFingerprint = fingerprint { +internal val miniplayerDimensionsCalculatorParentFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L") - literal { ytOutlinePictureInPictureWhite24 } + instructions( + resourceLiteral(ResourceType.DIMEN, "floaty_bar_button_top_margin") + ) } -/** - * Matches using the class found in [miniplayerModernViewParentFingerprint]. - */ -internal val miniplayerModernForwardButtonFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("L") - parameters() - literal { modernMiniplayerForwardButton } -} - -/** - * Matches using the class found in [miniplayerModernViewParentFingerprint]. - */ -internal val miniplayerModernOverlayViewFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - parameters() - literal { scrimOverlay } -} - -/** - * Matches using the class found in [miniplayerModernViewParentFingerprint]. - */ -internal val miniplayerModernRewindButtonFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("L") - parameters() - literal { modernMiniplayerRewindButton } -} - -internal val miniplayerModernViewParentFingerprint = fingerprint { +internal val miniplayerModernViewParentFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/String;") parameters() - strings("player_overlay_modern_mini_player_controls") + instructions( + string("player_overlay_modern_mini_player_controls") + ) } -internal val miniplayerModernActionButtonFingerprint = fingerprint { +/** + * Matches using the class found in [miniplayerModernViewParentFingerprint]. + */ +internal val miniplayerModernAddViewListenerFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters("Landroid/view/View;") +} + +/** + * Matches using the class found in [miniplayerModernViewParentFingerprint]. + */ +internal val miniplayerModernCloseButtonFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters() - literal { modernMiniPlayerOverlayActionButton } + instructions( + resourceLiteral(ResourceType.ID, "modern_miniplayer_close"), + checkCast("Landroid/widget/ImageView;") + ) } -internal val miniplayerMinimumSizeFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - custom { method, _ -> - method.containsLiteralInstruction(192) && - method.containsLiteralInstruction(128) && - method.containsLiteralInstruction(miniplayerMaxSize) - } -} - -internal val miniplayerOverrideFingerprint = fingerprint { +/** + * Matches using the class found in [miniplayerModernViewParentFingerprint]. + */ +internal val miniplayerModernExpandButtonFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") - strings("appName") + parameters() + instructions( + resourceLiteral(ResourceType.ID, "modern_miniplayer_expand"), + checkCast("Landroid/widget/ImageView;") + ) } -internal val miniplayerOverrideNoContextFingerprint = fingerprint { +/** + * Matches using the class found in [miniplayerModernViewParentFingerprint]. + */ +internal val miniplayerModernExpandCloseDrawablesFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters("L") + instructions( + literal(ytOutlinePictureInPictureWhite24) + ) +} + +/** + * Matches using the class found in [miniplayerModernViewParentFingerprint]. + */ +internal val miniplayerModernForwardButtonFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("L") + parameters() + instructions( + resourceLiteral(ResourceType.ID, "modern_miniplayer_forward_button"), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 5) + ) +} + +internal val miniplayerModernOverlayViewFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + parameters() + instructions( + resourceLiteral(ResourceType.ID, "scrim_overlay"), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 5) + ) +} + +/** + * Matches using the class found in [miniplayerModernViewParentFingerprint]. + */ +internal val miniplayerModernRewindButtonFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("L") + parameters() + instructions( + resourceLiteral(ResourceType.ID, "modern_miniplayer_rewind_button"), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 5) + ) +} + +/** + * Matches using the class found in [miniplayerModernViewParentFingerprint]. + */ +internal val miniplayerModernActionButtonFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("L") + parameters() + instructions( + resourceLiteral(ResourceType.ID, "modern_miniplayer_overlay_action_button"), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 5) + ) +} + +internal val miniplayerMinimumSizeFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) + instructions( + resourceLiteral(ResourceType.DIMEN, "miniplayer_max_size"), + literal(192), // Default miniplayer width constant. + literal(128) // Default miniplayer height constant. + ) +} + +internal val miniplayerOverrideFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("L") + instructions( + string("appName"), + methodCall( + parameters = listOf("Landroid/content/Context;"), + returnType = "Z", + maxAfter = 10 + ) + ) +} + +internal val miniplayerOverrideNoContextFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returns("Z") - opcodes(Opcode.IGET_BOOLEAN) // Anchor to insert the instruction. + instructions( + opcode(Opcode.IGET_BOOLEAN) // Anchor to insert the instruction. + ) } -internal val miniplayerResponseModelSizeCheckFingerprint = fingerprint { +internal val miniplayerResponseModelSizeCheckFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters("Ljava/lang/Object;", "Ljava/lang/Object;") @@ -155,10 +188,18 @@ internal val miniplayerResponseModelSizeCheckFingerprint = fingerprint { ) } +internal val miniplayerOnCloseHandlerFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("Z") + instructions( + literal(MINIPLAYER_DISABLED_FEATURE_KEY) + ) +} + internal const val YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME = "Lcom/google/android/apps/youtube/app/common/player/overlay/YouTubePlayerOverlaysLayout;" -internal val playerOverlaysLayoutFingerprint = fingerprint { +internal val playerOverlaysLayoutFingerprint by fingerprint { custom { method, _ -> method.definingClass == YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt index 08f78f9dc..1e6ad3626 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch.kt @@ -13,9 +13,9 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod 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.addResourcesPatch -import app.revanced.patches.shared.misc.mapping.get +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.* import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playservice.* @@ -26,39 +26,17 @@ 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.Method -import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.FieldReference -import com.android.tools.smali.dexlib2.iface.reference.MethodReference -import com.android.tools.smali.dexlib2.iface.reference.TypeReference import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter -internal var floatyBarButtonTopMargin = -1L - private set - // Only available in 19.15 and upwards. internal var ytOutlineXWhite24 = -1L private set internal var ytOutlinePictureInPictureWhite24 = -1L private set -internal var scrimOverlay = -1L - private set -internal var modernMiniplayerClose = -1L - private set -internal var modernMiniplayerExpand = -1L - private set -internal var modernMiniplayerRewindButton = -1L - private set -internal var modernMiniplayerForwardButton = -1L - private set -internal var modernMiniPlayerOverlayActionButton = -1L - private set -internal var playerOverlays = -1L - private set -internal var miniplayerMaxSize = -1L - private set private val miniplayerResourcePatch = resourcePatch { dependsOn( @@ -67,72 +45,24 @@ private val miniplayerResourcePatch = resourcePatch { ) execute { - floatyBarButtonTopMargin = resourceMappings[ - "dimen", - "floaty_bar_button_top_margin", - ] - - scrimOverlay = resourceMappings[ - "id", - "scrim_overlay", - ] - - playerOverlays = resourceMappings[ - "layout", - "player_overlays", - ] - - - modernMiniplayerClose = resourceMappings[ - "id", - "modern_miniplayer_close", - ] - - modernMiniplayerExpand = resourceMappings[ - "id", - "modern_miniplayer_expand", - ] - - modernMiniplayerRewindButton = resourceMappings[ - "id", - "modern_miniplayer_rewind_button", - ] - - modernMiniplayerForwardButton = resourceMappings[ - "id", - "modern_miniplayer_forward_button", - ] - - modernMiniPlayerOverlayActionButton = resourceMappings[ - "id", - "modern_miniplayer_overlay_action_button" - ] - // Resource id is not used during patching, but is used by extension. // Verify the resource is present while patching. - resourceMappings[ - "id", + getResourceId( + ResourceType.ID, "modern_miniplayer_subtitle_text", - ] + ) // Only required for exactly 19.16 if (!is_19_17_or_greater) { - ytOutlinePictureInPictureWhite24 = resourceMappings[ - "drawable", + ytOutlinePictureInPictureWhite24 = getResourceId( + ResourceType.DRAWABLE, "yt_outline_picture_in_picture_white_24", - ] + ) - ytOutlineXWhite24 = resourceMappings[ - "drawable", + ytOutlineXWhite24 = getResourceId( + ResourceType.DRAWABLE, "yt_outline_x_white_24", - ] - } - - if (is_19_26_or_greater) { - miniplayerMaxSize = resourceMappings[ - "dimen", - "miniplayer_max_size", - ] + ) } } } @@ -167,6 +97,7 @@ val miniplayerPatch = bytecodePatch( val preferences = mutableSetOf() + preferences += if (is_20_03_or_greater) { ListPreference("revanced_miniplayer_type") @@ -299,24 +230,6 @@ val miniplayerPatch = bytecodePatch( ) } - fun MutableMethod.hookInflatedView( - literalValue: Long, - hookedClassType: String, - extensionMethodName: String, - ) { - val imageViewIndex = indexOfFirstInstructionOrThrow( - indexOfFirstLiteralInstructionOrThrow(literalValue), - ) { - opcode == Opcode.CHECK_CAST && getReference()?.type == hookedClassType - } - - val register = getInstruction(imageViewIndex).registerA - addInstruction( - imageViewIndex + 1, - "invoke-static { v$register }, $extensionMethodName", - ) - } - // region Enable tablet miniplayer. miniplayerOverrideNoContextFingerprint.match( @@ -328,18 +241,15 @@ val miniplayerPatch = bytecodePatch( // endregion // region Legacy tablet miniplayer hooks. - val appNameStringIndex = miniplayerOverrideFingerprint.let { - it.method.indexOfFirstInstructionOrThrow(it.stringMatches!!.first().index) { - val reference = getReference() - reference?.parameterTypes?.firstOrNull() == "Landroid/content/Context;" + miniplayerOverrideFingerprint.let { + val appNameStringIndex = it.instructionMatches.last().index + navigate(it.originalMethod).to(appNameStringIndex).stop().apply { + findReturnIndicesReversed().forEach { index -> insertLegacyTabletMiniplayerOverride(index) } } } - navigate(miniplayerOverrideFingerprint.originalMethod).to(appNameStringIndex).stop().apply { - findReturnIndicesReversed().forEach { index -> insertLegacyTabletMiniplayerOverride(index) } - } miniplayerResponseModelSizeCheckFingerprint.let { - it.method.insertLegacyTabletMiniplayerOverride(it.patternMatch!!.endIndex) + it.method.insertLegacyTabletMiniplayerOverride(it.instructionMatches.last().index) } // endregion @@ -390,7 +300,6 @@ val miniplayerPatch = bytecodePatch( MINIPLAYER_INITIAL_SIZE_FEATURE_KEY, ) val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.LONG_TO_INT) - val register = getInstruction(targetIndex).registerA addInstructions( @@ -403,16 +312,16 @@ val miniplayerPatch = bytecodePatch( } // Override a minimum size constant. - miniplayerMinimumSizeFingerprint.method.apply { - val index = indexOfFirstInstructionOrThrow { - opcode == Opcode.CONST_16 && (this as NarrowLiteralInstruction).narrowLiteral == 192 - } - val register = getInstruction(index).registerA + miniplayerMinimumSizeFingerprint.let { + it.method.apply { + val index = it.instructionMatches[1].index + val register = getInstruction(index).registerA - // Smaller sizes can be used, but the miniplayer will always start in size 170 if set any smaller. - // The 170 initial limit probably could be patched to allow even smaller initial sizes, - // but 170 is already half the horizontal space and smaller does not seem useful. - replaceInstruction(index, "const/16 v$register, 170") + // Smaller sizes can be used, but the miniplayer will always start in size 170 if set any smaller. + // The 170 initial limit probably could be patched to allow even smaller initial sizes, + // but 170 is already half the horizontal space and smaller does not seem useful. + replaceInstruction(index, "const/16 v$register, 170") + } } } @@ -433,6 +342,11 @@ val miniplayerPatch = bytecodePatch( MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY, "getHorizontalDrag", ) + + miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride( + MINIPLAYER_ANIMATED_EXPAND_FEATURE_KEY, + "getMaximizeAnimation", + ) } // endregion @@ -440,7 +354,7 @@ val miniplayerPatch = bytecodePatch( // region Fix 19.16 using mixed up drawables for tablet modern. // YT fixed this mistake in 19.17. // Fix this, by swapping the drawable resource values with each other. - if (ytOutlinePictureInPictureWhite24 >= 0) { + if (!is_19_17_or_greater) { miniplayerModernExpandCloseDrawablesFingerprint.match( miniplayerModernViewParentFingerprint.originalClassDef, ).method.apply { @@ -461,55 +375,22 @@ val miniplayerPatch = bytecodePatch( // region Add hooks to hide modern miniplayer buttons. listOf( - Triple( - miniplayerModernExpandButtonFingerprint, - modernMiniplayerExpand, - "hideMiniplayerExpandClose", - ), - Triple( - miniplayerModernCloseButtonFingerprint, - modernMiniplayerClose, - "hideMiniplayerExpandClose", - ), - Triple( - miniplayerModernActionButtonFingerprint, - modernMiniPlayerOverlayActionButton, - "hideMiniplayerActionButton" - ), - Triple( - miniplayerModernRewindButtonFingerprint, - modernMiniplayerRewindButton, - "hideMiniplayerRewindForward", - ), - Triple( - miniplayerModernForwardButtonFingerprint, - modernMiniplayerForwardButton, - "hideMiniplayerRewindForward", - ), - Triple( - miniplayerModernOverlayViewFingerprint, - scrimOverlay, - "adjustMiniplayerOpacity", - ), - ).forEach { (fingerprint, literalValue, methodName) -> + miniplayerModernExpandButtonFingerprint to "hideMiniplayerExpandClose", + miniplayerModernCloseButtonFingerprint to "hideMiniplayerExpandClose", + miniplayerModernActionButtonFingerprint to "hideMiniplayerActionButton", + miniplayerModernRewindButtonFingerprint to "hideMiniplayerRewindForward", + miniplayerModernForwardButtonFingerprint to "hideMiniplayerRewindForward", + miniplayerModernOverlayViewFingerprint to "adjustMiniplayerOpacity" + ).forEach { (fingerprint, methodName) -> fingerprint.match( - miniplayerModernViewParentFingerprint.originalClassDef + miniplayerModernViewParentFingerprint.classDef, ).method.apply { - val literalIndex = indexOfFirstLiteralInstructionOrThrow(literalValue) - val checkCastIndex = indexOfFirstInstruction(literalIndex) { - opcode == Opcode.CHECK_CAST && - getReference()?.type == "Landroid/widget/ImageView;" - } - val viewIndex = if (checkCastIndex >= 0) { - checkCastIndex - } else { - indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT_OBJECT) - } - val viewRegister = getInstruction(viewIndex).registerA + val index = fingerprint.instructionMatches.last().index + val register = getInstruction(index).registerA addInstruction( - viewIndex + 1, - "invoke-static { v$viewRegister }, $EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/view/View;)V" + index + 1, + "invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/view/View;)V", ) } } @@ -552,10 +433,10 @@ val miniplayerPatch = bytecodePatch( ).toMutable().apply { addInstructions( """ - invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V - invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V - return-void - """ + invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V + invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V + return-void + """ ) } ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/Fingerprints.kt index 0c31cc83b..7ac0ce2a1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/Fingerprints.kt @@ -3,7 +3,7 @@ package app.revanced.patches.youtube.layout.panels.popup import com.android.tools.smali.dexlib2.AccessFlags import app.revanced.patcher.fingerprint -internal val engagementPanelControllerFingerprint = fingerprint { +internal val engagementPanelControllerFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returns("L") strings( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatch.kt deleted file mode 100644 index 5c20556a8..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatch.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.youtube.layout.player.background - -import app.revanced.patcher.patch.resourcePatch -import app.revanced.patches.youtube.layout.buttons.overlay.hidePlayerOverlayButtonsPatch - -@Suppress("unused") -@Deprecated("Functionality added to hidePlayerOverlayButtonsPatch", ReplaceWith("hidePlayerOverlayButtonsPatch")) -val playerControlsBackgroundPatch = resourcePatch( - description = "Removes the dark background surrounding the video player control buttons.", -) { - dependsOn(hidePlayerOverlayButtonsPatch) -} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/Fingerprints.kt index a8aef3734..f5783b80c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/Fingerprints.kt @@ -1,21 +1,49 @@ package app.revanced.patches.youtube.layout.player.fullscreen import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.opcode import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode -internal const val OPEN_VIDEOS_FULLSCREEN_PORTRAIT_FEATURE_FLAG = 45666112L - -internal val openVideosFullscreenPortraitFingerprint = fingerprint { +/** + * 19.46+ + */ +internal val openVideosFullscreenPortraitFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L", "Lj\$/util/Optional;") - literal { - OPEN_VIDEOS_FULLSCREEN_PORTRAIT_FEATURE_FLAG - } + instructions( + opcode(Opcode.MOVE_RESULT), // Conditional check to modify. + // Open videos fullscreen portrait feature flag. + literal(45666112L, maxAfter = 5), // Cannot be more than 5. + opcode(Opcode.MOVE_RESULT, maxAfter = 10), + ) } -internal val openVideosFullscreenHookPatchExtensionFingerprint = fingerprint { +/** + * Pre 19.46. + */ +internal val openVideosFullscreenPortraitLegacyFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters("L", "Lj\$/util/Optional;") + opcodes( + Opcode.GOTO, + Opcode.SGET_OBJECT, + Opcode.GOTO, + Opcode.SGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQ, + Opcode.IF_EQ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT // Conditional check to modify. + ) +} + +internal val openVideosFullscreenHookPatchExtensionFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returns("Z") parameters() diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreen.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreen.kt deleted file mode 100644 index 89311b08c..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreen.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.layout.player.fullscreen - -import app.revanced.patcher.patch.bytecodePatch - -@Suppress("unused") -@Deprecated("Renamed to openVideosFullscreenPatch", ReplaceWith("openVideosFullscreenPatch")) -val openVideosFullscreen = bytecodePatch{ - dependsOn(openVideosFullscreenPatch) -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt index 76086c0e4..79253d46b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenHookPatch.kt @@ -1,11 +1,15 @@ package app.revanced.patches.youtube.layout.player.fullscreen +import app.revanced.patcher.Fingerprint +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.youtube.layout.shortsplayer.openShortsInRegularPlayerPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.util.insertLiteralOverride +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/OpenVideosFullscreenHookPatch;" @@ -20,13 +24,40 @@ internal val openVideosFullscreenHookPatch = bytecodePatch { ) execute { - if (!is_19_46_or_greater) { - return@execute + var fingerprint: Fingerprint + var insertIndex: Int + + if (is_19_46_or_greater) { + fingerprint = openVideosFullscreenPortraitFingerprint + insertIndex = fingerprint.instructionMatches.first().index + + openVideosFullscreenPortraitFingerprint.let { + // Remove A/B feature call that forces what this patch already does. + // Cannot use the A/B flag to accomplish the same goal because 19.50+ + // Shorts fullscreen regular player does not use fullscreen + // if the player is minimized and it must be forced using other conditional check. + it.method.insertLiteralOverride( + it.instructionMatches.last().index, + false + ) + } + } else { + fingerprint = openVideosFullscreenPortraitLegacyFingerprint + insertIndex = fingerprint.instructionMatches.last().index } - openVideosFullscreenPortraitFingerprint.method.insertLiteralOverride( - OPEN_VIDEOS_FULLSCREEN_PORTRAIT_FEATURE_FLAG, - "$EXTENSION_CLASS_DESCRIPTOR->openVideoFullscreenPortrait(Z)Z" - ) + fingerprint.let { + it.method.apply { + val register = getInstruction(insertIndex).registerA + + addInstructions( + insertIndex + 1, + """ + invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->doNotOpenVideoFullscreenPortrait(Z)Z + move-result v$register + """ + ) + } + } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenPatch.kt index 1c76b56e4..7b5aa145f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenPatch.kt @@ -1,12 +1,9 @@ package app.revanced.patches.youtube.layout.player.fullscreen -import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference -import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater -import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.util.returnEarly @@ -20,11 +17,12 @@ val openVideosFullscreenPatch = bytecodePatch( openVideosFullscreenHookPatch, settingsPatch, addResourcesPatch, - versionCheckPatch ) compatibleWith( "com.google.android.youtube"( + "19.34.42", + "19.43.41", "19.47.53", "20.07.39", "20.12.46", @@ -33,10 +31,6 @@ val openVideosFullscreenPatch = bytecodePatch( ) execute { - if (!is_19_46_or_greater) { - throw PatchException("'Open videos fullscreen' requires 19.46.42 or greater") - } - addResources("youtube", "layout.player.fullscreen.openVideosFullscreen") PreferenceScreen.PLAYER.addPreferences( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt index 35f81a643..b96b36ea4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt @@ -3,43 +3,15 @@ package app.revanced.patches.youtube.layout.player.overlay import app.revanced.patcher.extensions.InstructionExtensions.addInstruction 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.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.InputType import app.revanced.patches.shared.misc.settings.preference.TextPreference import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.util.indexOfFirstLiteralInstructionOrThrow import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -internal var scrimOverlayId = -1L - private set - -private val customPlayerOverlayOpacityResourcePatch = resourcePatch { - dependsOn( - settingsPatch, - resourceMappingPatch, - addResourcesPatch, - ) - - execute { - addResources("youtube", "layout.player.overlay.customPlayerOverlayOpacityResourcePatch") - - PreferenceScreen.PLAYER.addPreferences( - TextPreference("revanced_player_overlay_opacity", inputType = InputType.NUMBER), - ) - - scrimOverlayId = resourceMappings[ - "id", - "scrim_overlay", - ] - } -} - private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/CustomPlayerOverlayOpacityPatch;" @@ -48,7 +20,10 @@ val customPlayerOverlayOpacityPatch = bytecodePatch( name = "Custom player overlay opacity", description = "Adds an option to change the opacity of the video player background when player controls are visible.", ) { - dependsOn(customPlayerOverlayOpacityResourcePatch) + dependsOn(settingsPatch, + resourceMappingPatch, + addResourcesPatch, + ) compatibleWith( "com.google.android.youtube"( @@ -62,18 +37,23 @@ val customPlayerOverlayOpacityPatch = bytecodePatch( ) execute { - createPlayerOverviewFingerprint.method.apply { - val viewRegisterIndex = - indexOfFirstLiteralInstructionOrThrow(scrimOverlayId) + 3 - val viewRegister = - getInstruction(viewRegisterIndex).registerA + addResources("youtube", "layout.player.overlay.customPlayerOverlayOpacityResourcePatch") - val insertIndex = viewRegisterIndex + 1 - addInstruction( - insertIndex, - "invoke-static { v$viewRegister }, " + - "$EXTENSION_CLASS_DESCRIPTOR->changeOpacity(Landroid/widget/ImageView;)V", - ) + PreferenceScreen.PLAYER.addPreferences( + TextPreference("revanced_player_overlay_opacity", inputType = InputType.NUMBER), + ) + + createPlayerOverviewFingerprint.let { + it.method.apply { + val viewRegisterIndex = it.instructionMatches.last().index + val viewRegister = getInstruction(viewRegisterIndex).registerA + + addInstruction( + viewRegisterIndex + 1, + "invoke-static { v$viewRegister }, " + + "$EXTENSION_CLASS_DESCRIPTOR->changeOpacity(Landroid/widget/ImageView;)V", + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/Fingerprints.kt index 726986840..c5f6909c4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/Fingerprints.kt @@ -1,18 +1,14 @@ package app.revanced.patches.youtube.layout.player.overlay +import app.revanced.patcher.checkCast import app.revanced.patcher.fingerprint -import app.revanced.util.literal -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral -internal val createPlayerOverviewFingerprint = fingerprint { - accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) +internal val createPlayerOverviewFingerprint by fingerprint { returns("V") - opcodes( - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, + instructions( + resourceLiteral(ResourceType.ID, "scrim_overlay"), + checkCast("Landroid/widget/ImageView;", maxAfter = 10) ) - literal { scrimOverlayId } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/Fingerprints.kt index 54fda75c8..e87999f68 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/Fingerprints.kt @@ -1,26 +1,33 @@ package app.revanced.patches.youtube.layout.returnyoutubedislike import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.string import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val dislikeFingerprint = fingerprint { +internal val dislikeFingerprint by fingerprint { returns("V") - strings("like/dislike") + instructions( + string("like/dislike") + ) } -internal val likeFingerprint = fingerprint { +internal val likeFingerprint by fingerprint { returns("V") - strings("like/like") + instructions( + string("like/like") + ) } -internal val removeLikeFingerprint = fingerprint { +internal val removeLikeFingerprint by fingerprint { returns("V") - strings("like/removelike") + instructions( + string("like/removelike") + ) } -internal val rollingNumberMeasureAnimatedTextFingerprint = fingerprint { +internal val rollingNumberMeasureAnimatedTextFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Lj\$/util/Optional;") parameters("L", "Ljava/lang/String;", "L") @@ -41,7 +48,7 @@ internal val rollingNumberMeasureAnimatedTextFingerprint = fingerprint { /** * Matches to class found in [rollingNumberMeasureStaticLabelParentFingerprint]. */ -internal val rollingNumberMeasureStaticLabelFingerprint = fingerprint { +internal val rollingNumberMeasureStaticLabelFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("F") parameters("Ljava/lang/String;") @@ -53,14 +60,16 @@ internal val rollingNumberMeasureStaticLabelFingerprint = fingerprint { ) } -internal val rollingNumberMeasureStaticLabelParentFingerprint = fingerprint { +internal val rollingNumberMeasureStaticLabelParentFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/String;") parameters() - strings("RollingNumberFontProperties{paint=") + instructions( + string("RollingNumberFontProperties{paint=") + ) } -internal val rollingNumberSetterFingerprint = fingerprint { +internal val rollingNumberSetterFingerprint by fingerprint { opcodes( Opcode.INVOKE_DIRECT, Opcode.IGET_OBJECT, @@ -69,7 +78,7 @@ internal val rollingNumberSetterFingerprint = fingerprint { strings("RollingNumberType required properties missing! Need") } -internal val rollingNumberTextViewFingerprint = fingerprint { +internal val rollingNumberTextViewFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L", "F", "F") @@ -87,15 +96,19 @@ internal val rollingNumberTextViewFingerprint = fingerprint { } } -internal val textComponentConstructorFingerprint = fingerprint { +internal val textComponentConstructorFingerprint by fingerprint { accessFlags(AccessFlags.CONSTRUCTOR, AccessFlags.PRIVATE) - strings("TextComponent") + instructions( + string("TextComponent") + ) } -internal val textComponentDataFingerprint = fingerprint { +internal val textComponentDataFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameters("L", "L") - strings("text") + instructions( + string("text") + ) custom { _, classDef -> classDef.fields.find { it.type == "Ljava/util/BitSet;" } != null } @@ -104,18 +117,20 @@ internal val textComponentDataFingerprint = fingerprint { /** * Matches against the same class found in [textComponentConstructorFingerprint]. */ -internal val textComponentLookupFingerprint = fingerprint { +internal val textComponentLookupFingerprint by fingerprint { accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL) returns("L") parameters("L") - strings("…") + instructions( + string("…") + ) } -internal const val LITHO_NEW_TEXT_COMPONENT_FEATURE_FLAG = 45675738L - -internal val textComponentFeatureFlagFingerprint = fingerprint { +internal val textComponentFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.FINAL) returns("Z") parameters() - literal { LITHO_NEW_TEXT_COMPONENT_FEATURE_FLAG } -} + instructions ( + literal(45675738L) + ) +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt index b65b8f6c4..5d5a7360c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt @@ -104,7 +104,7 @@ val returnYouTubeDislikePatch = bytecodePatch( // region Hook like/dislike/remove like button clicks to send votes to the API. - mapOf( + arrayOf( likeFingerprint to Vote.LIKE, dislikeFingerprint to Vote.DISLIKE, removeLikeFingerprint to Vote.REMOVE_LIKE, @@ -122,10 +122,10 @@ val returnYouTubeDislikePatch = bytecodePatch( // region Hook code for creation and cached lookup of text Spans. - // Alternatively the hook can be made at tht it fails to update the Span when the user dislikes, - // // since the underlying (likes only) tee creation of Spans in TextComponentSpec, - // And it works in all situations excepxt did not change. + // Alternatively the hook can be made in the creation of Spans in TextComponentSpec. + // And it works in all situations except if the likes do not such as disliking. // This hook handles all situations, as it's where the created Spans are stored and later reused. + // Find the field name of the conversion context. val conversionContextField = textComponentConstructorFingerprint.originalClassDef.fields.find { it.type == conversionContextFingerprintToString.originalClassDef.type @@ -137,41 +137,35 @@ val returnYouTubeDislikePatch = bytecodePatch( val textDataClassType = textComponentDataFingerprint.originalClassDef.type val insertIndex: Int - val tempRegister: Int val charSequenceRegister: Int - if (is_19_33_or_greater && !is_20_10_or_greater) { - insertIndex = indexOfFirstInstructionOrThrow { + if (is_19_33_or_greater && !is_20_10_or_greater) { + val index = indexOfFirstInstructionOrThrow { (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) && getReference()?.returnType == textDataClassType } - tempRegister = getInstruction(insertIndex + 1).registerA - - // Find the instruction that sets the span to an instance field. - // The instruction is only a few lines after the creation of the instance. - charSequenceRegister = getInstruction( - indexOfFirstInstructionOrThrow(insertIndex) { - opcode == Opcode.INVOKE_VIRTUAL && + insertIndex = indexOfFirstInstructionOrThrow(index) { + opcode == Opcode.INVOKE_VIRTUAL && getReference()?.parameterTypes?.firstOrNull() == "Ljava/lang/CharSequence;" - }, - ).registerD + } + + charSequenceRegister = getInstruction(insertIndex).registerD } else { insertIndex = indexOfFirstInstructionOrThrow { opcode == Opcode.NEW_INSTANCE && getReference()?.type == textDataClassType } - tempRegister = getInstruction(insertIndex).registerA - - charSequenceRegister = getInstruction( - indexOfFirstInstructionOrThrow(insertIndex) { - opcode == Opcode.IPUT_OBJECT && + val charSequenceIndex = indexOfFirstInstructionOrThrow(insertIndex) { + opcode == Opcode.IPUT_OBJECT && getReference()?.type == "Ljava/lang/CharSequence;" - }, - ).registerA + } + charSequenceRegister = getInstruction(charSequenceIndex).registerA } + val tempRegister = findFreeRegister(insertIndex, charSequenceRegister) + addInstructionsAtControlFlowLabel( insertIndex, """ @@ -206,11 +200,9 @@ val returnYouTubeDislikePatch = bytecodePatch( // region Hook rolling numbers. - val dislikesIndex = rollingNumberSetterFingerprint.patternMatch!!.endIndex - rollingNumberSetterFingerprint.method.apply { val insertIndex = 1 - + val dislikesIndex = rollingNumberSetterFingerprint.instructionMatches.last().index val charSequenceInstanceRegister = getInstruction(0).registerA val charSequenceFieldReference = @@ -227,17 +219,16 @@ val returnYouTubeDislikePatch = bytecodePatch( invoke-static {v$conversionContextRegister, v$freeRegister}, $EXTENSION_CLASS_DESCRIPTOR->onRollingNumberLoaded(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String; move-result-object v$freeRegister iput-object v$freeRegister, v$charSequenceInstanceRegister, $charSequenceFieldReference - """, + """ ) } + // Rolling Number text views use the measured width of the raw string for layout. + // Modify the measure text calculation to include the left drawable separator if needed. rollingNumberMeasureAnimatedTextFingerprint.let { - // Rolling Number text views use the measured width of the raw string for layout. - // Modify the measure text calculation to include the left drawable separator if needed. - val patternMatch = it.patternMatch!! - // Verify the opcodes are at the start of the method. - if (patternMatch.startIndex != 0) throw PatchException("Unexpected opcode location") - val endIndex = patternMatch.endIndex + // Additional check to verify the opcodes are at the start of the method + if (it.instructionMatches.first().index != 0) throw PatchException("Unexpected opcode location") + val endIndex = it.instructionMatches.last().index it.method.apply { val measuredTextWidthRegister = getInstruction(endIndex).registerA @@ -257,7 +248,7 @@ val returnYouTubeDislikePatch = bytecodePatch( rollingNumberMeasureStaticLabelFingerprint.match( rollingNumberMeasureStaticLabelParentFingerprint.originalClassDef, ).let { - val measureTextIndex = it.patternMatch!!.startIndex + 1 + val measureTextIndex = it.instructionMatches.first().index + 1 it.method.apply { val freeRegister = getInstruction(0).registerA @@ -266,7 +257,7 @@ val returnYouTubeDislikePatch = bytecodePatch( """ move-result v$freeRegister invoke-static {p1, v$freeRegister}, $EXTENSION_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F - """, + """ ) } } @@ -285,10 +276,8 @@ val returnYouTubeDislikePatch = bytecodePatch( getReference()?.name == "setText" } - val textViewRegister = - getInstruction(setTextIndex).registerC - val textSpanRegister = - getInstruction(setTextIndex).registerD + val textViewRegister = getInstruction(setTextIndex).registerC + val textSpanRegister = getInstruction(setTextIndex).registerD addInstructions( setTextIndex, diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/Fingerprints.kt index 2dbff83a2..a25403c4b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/Fingerprints.kt @@ -1,27 +1,29 @@ package app.revanced.patches.youtube.layout.searchbar import app.revanced.patcher.fingerprint +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import app.revanced.patches.youtube.layout.hide.general.yoodlesImageViewFingerprint -import app.revanced.util.containsLiteralInstruction -import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags -internal val setWordmarkHeaderFingerprint = fingerprint { +internal val setWordmarkHeaderFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Landroid/widget/ImageView;") - custom { methodDef, _ -> - methodDef.containsLiteralInstruction(ytPremiumWordmarkHeaderId) && - methodDef.containsLiteralInstruction(ytWordmarkHeaderId) - } + instructions( + resourceLiteral(ResourceType.ATTR, "ytPremiumWordmarkHeader"), + resourceLiteral(ResourceType.ATTR, "ytWordmarkHeader") + ) } /** * Matches the same method as [yoodlesImageViewFingerprint]. */ -internal val wideSearchbarLayoutFingerprint = fingerprint { +internal val wideSearchbarLayoutFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Landroid/view/View;") parameters("L", "L") - literal { actionBarRingoId } + instructions( + resourceLiteral(ResourceType.LAYOUT, "action_bar_ringo"), + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt index 4f06635d1..61dc648e4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt @@ -3,14 +3,13 @@ package app.revanced.patches.youtube.layout.searchbar import app.revanced.patcher.extensions.InstructionExtensions.addInstruction 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.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch +import app.revanced.patches.youtube.misc.playservice.is_20_31_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.util.addInstructionsAtControlFlowLabel @@ -20,38 +19,11 @@ import app.revanced.util.indexOfFirstInstructionOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference +import java.util.logging.Logger private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/WideSearchbarPatch;" -internal var ytWordmarkHeaderId = -1L - private set -internal var ytPremiumWordmarkHeaderId = -1L - private set -internal var actionBarRingoId = -1L - private set - -private val wideSearchbarResourcePatch = resourcePatch { - dependsOn(resourceMappingPatch) - - execute { - ytWordmarkHeaderId = resourceMappings[ - "attr", - "ytWordmarkHeader", - ] - - ytPremiumWordmarkHeaderId = resourceMappings[ - "attr", - "ytPremiumWordmarkHeader", - ] - - actionBarRingoId = resourceMappings[ - "layout", - "action_bar_ringo", - ] - } -} - val wideSearchbarPatch = bytecodePatch( name = "Wide search bar", description = "Adds an option to replace the search icon with a wide search bar. " + @@ -61,7 +33,8 @@ val wideSearchbarPatch = bytecodePatch( sharedExtensionPatch, settingsPatch, addResourcesPatch, - wideSearchbarResourcePatch, + resourceMappingPatch, + versionCheckPatch ) compatibleWith( @@ -76,6 +49,15 @@ val wideSearchbarPatch = bytecodePatch( ) execute { + if (is_20_31_or_greater) { + // YT removed the legacy text search text field all code required to use it. + // This functionality could be restored by adding a search text field to the toolbar + // with a listener that artificially clicks the toolbar search button. + Logger.getLogger(this::class.java.name).severe( + "Wide searchbar is not compatible with 20.31+") + return@execute + } + addResources("youtube", "layout.searchbar.wideSearchbarPatch") PreferenceScreen.FEED.addPreferences( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/Fingerprints.kt index 25d291809..9aeee8d0d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/Fingerprints.kt @@ -1,69 +1,75 @@ package app.revanced.patches.youtube.layout.seekbar +import app.revanced.patcher.anyInstruction import app.revanced.patcher.fingerprint -import app.revanced.util.containsLiteralInstruction -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patcher.string +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal val fullscreenSeekbarThumbnailsFingerprint = fingerprint { +internal val fullscreenSeekbarThumbnailsFingerprint by fingerprint { returns("Z") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters() - literal { 45398577 } + instructions( + literal(45398577) + ) } -internal val playerSeekbarColorFingerprint = fingerprint { +internal val playerSeekbarColorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - custom { method, _ -> - method.containsLiteralInstruction(inlineTimeBarColorizedBarPlayedColorDarkId) && - method.containsLiteralInstruction(inlineTimeBarPlayedNotHighlightedColorId) - } + instructions( + resourceLiteral(ResourceType.COLOR, "inline_time_bar_played_not_highlighted_color"), + resourceLiteral(ResourceType.COLOR, "inline_time_bar_colorized_bar_played_color_dark") + ) } -internal val setSeekbarClickedColorFingerprint = fingerprint { +// class is ControlsOverlayStyle in 20.32 and lower, and obfuscated in 20.33+ +internal val setSeekbarClickedColorFingerprint by fingerprint { opcodes(Opcode.CONST_HIGH16) - strings("YOUTUBE", "PREROLL", "POSTROLL") - custom { _, classDef -> - classDef.endsWith("ControlsOverlayStyle;") - } + strings("YOUTUBE", "PREROLL", "POSTROLL", "REMOTE_LIVE", "AD_LARGE_CONTROLS") } -internal val shortsSeekbarColorFingerprint = fingerprint { +internal val shortsSeekbarColorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - literal { reelTimeBarPlayedColorId } + instructions( + resourceLiteral(ResourceType.COLOR, "reel_time_bar_played_color") + ) } -internal val playerSeekbarHandle1ColorFingerprint = fingerprint { +internal val playerSeekbarHandle1ColorFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) + instructions( + resourceLiteral(ResourceType.COLOR, "inline_time_bar_live_seekable_range"), + resourceLiteral(ResourceType.ATTR, "ytStaticBrandRed"), + ) +} + +internal val playerSeekbarHandle2ColorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameters("Landroid/content/Context;") - custom { method, _ -> - method.containsLiteralInstruction(ytTextSecondaryId) && - method.containsLiteralInstruction(ytStaticBrandRedId) - } + instructions( + resourceLiteral(ResourceType.ATTR, "ytTextSecondary"), + resourceLiteral(ResourceType.ATTR, "ytStaticBrandRed"), + ) } -internal val playerSeekbarHandle2ColorFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - parameters("Landroid/content/Context;") - custom { method, _ -> - method.containsLiteralInstruction(inlineTimeBarLiveSeekableRangeId) && - method.containsLiteralInstruction(ytStaticBrandRedId) - } -} - - -internal val watchHistoryMenuUseProgressDrawableFingerprint = fingerprint { +internal val watchHistoryMenuUseProgressDrawableFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L") - literal { -1712394514 } + instructions( + methodCall("Landroid/widget/ProgressBar;", "setMax"), + opcode(Opcode.MOVE_RESULT), + literal(-1712394514) + ) } -internal val lithoLinearGradientFingerprint = fingerprint { +internal val lithoLinearGradientFingerprint by fingerprint { accessFlags(AccessFlags.STATIC) returns("Landroid/graphics/LinearGradient;") parameters("F", "F", "F", "F", "[I", "[F") @@ -72,76 +78,72 @@ internal val lithoLinearGradientFingerprint = fingerprint { /** * 19.49+ */ -internal val playerLinearGradientFingerprint = fingerprint { +internal val playerLinearGradientFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) parameters("I", "I", "I", "I", "Landroid/content/Context;", "I") returns("Landroid/graphics/LinearGradient;") - opcodes( - Opcode.FILLED_NEW_ARRAY, - Opcode.MOVE_RESULT_OBJECT + instructions( + resourceLiteral(ResourceType.COLOR, "yt_youtube_magenta"), + + opcode(Opcode.FILLED_NEW_ARRAY, maxAfter = 5), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0) ) - literal { ytYoutubeMagentaColorId } } /** * 19.25 - 19.47 */ -internal val playerLinearGradientLegacyFingerprint = fingerprint { +internal val playerLinearGradientLegacyFingerprint by fingerprint { returns("V") - opcodes( - Opcode.FILLED_NEW_ARRAY, - Opcode.MOVE_RESULT_OBJECT + instructions( + resourceLiteral(ResourceType.COLOR, "yt_youtube_magenta"), + + opcode(Opcode.FILLED_NEW_ARRAY), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0), ) - literal { ytYoutubeMagentaColorId } } -internal const val launchScreenLayoutTypeLotteFeatureFlag = 268507948L +internal const val launchScreenLayoutTypeLotteFeatureLegacyFlag = 268507948L +internal const val launchScreenLayoutTypeLotteFeatureFlag = 1073814316L -internal val launchScreenLayoutTypeFingerprint = fingerprint { +internal val launchScreenLayoutTypeFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") + instructions( + anyInstruction( + literal(launchScreenLayoutTypeLotteFeatureLegacyFlag), + literal(launchScreenLayoutTypeLotteFeatureFlag) + ) + ) custom { method, _ -> val firstParameter = method.parameterTypes.firstOrNull() // 19.25 - 19.45 - (firstParameter == "Lcom/google/android/apps/youtube/app/watchwhile/MainActivity;" - || firstParameter == "Landroid/app/Activity;") // 19.46+ - && method.containsLiteralInstruction(launchScreenLayoutTypeLotteFeatureFlag) + firstParameter == "Lcom/google/android/apps/youtube/app/watchwhile/MainActivity;" + || firstParameter == "Landroid/app/Activity;" // 19.46+ } } internal const val LOTTIE_ANIMATION_VIEW_CLASS_TYPE = "Lcom/airbnb/lottie/LottieAnimationView;" -internal val lottieAnimationViewSetAnimationIntFingerprint = fingerprint { +internal val lottieAnimationViewSetAnimationIntFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters("I") returns("V") - custom { methodDef, classDef -> - classDef.type == LOTTIE_ANIMATION_VIEW_CLASS_TYPE && methodDef.indexOfFirstInstruction { - val reference = getReference() - reference?.definingClass == "Lcom/airbnb/lottie/LottieAnimationView;" - && reference.name == "isInEditMode" - } >= 0 + instructions( + methodCall("this", "isInEditMode") + ) + custom { _, classDef -> + classDef.type == LOTTIE_ANIMATION_VIEW_CLASS_TYPE } } -internal val lottieAnimationViewSetAnimationStreamFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - parameters("L") - returns("V") - custom { methodDef, classDef -> - classDef.type == LOTTIE_ANIMATION_VIEW_CLASS_TYPE && methodDef.indexOfFirstInstruction { - val reference = getReference() - reference?.definingClass == "Ljava/util/Set;" - && reference.name == "add" - } >= 0 && methodDef.containsLiteralInstruction(0) - } -} - -internal val lottieCompositionFactoryZipFingerprint = fingerprint { +internal val lottieCompositionFactoryZipFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) - parameters("Landroid/content/Context;", "Ljava/lang/String;", "Ljava/lang/String;") + parameters("Landroid/content/Context;", "Ljava/util/zip/ZipInputStream;", "Ljava/lang/String;") returns("L") - strings(".zip", ".lottie") + instructions( + string("Unable to parse composition"), + string(" however it was not found in the animation.") + ) } /** @@ -149,11 +151,12 @@ internal val lottieCompositionFactoryZipFingerprint = fingerprint { * * [Original method](https://github.com/airbnb/lottie-android/blob/26ad8bab274eac3f93dccccfa0cafc39f7408d13/lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java#L386) */ -internal val lottieCompositionFactoryFromJsonInputStreamFingerprint = fingerprint { +internal val lottieCompositionFactoryFromJsonInputStreamFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) parameters("Ljava/io/InputStream;", "Ljava/lang/String;") returns("L") - literal { 2 } + instructions( + anyInstruction(literal(2), literal(3)) + ) } - diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt index 76fe99b31..b00df5a5b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorPatch.kt @@ -5,14 +5,13 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.fingerprint import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable -import app.revanced.patches.shared.misc.mapping.get import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.youtube.layout.theme.lithoColorHookPatch import app.revanced.patches.youtube.layout.theme.lithoColorOverrideHook import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch @@ -20,8 +19,9 @@ import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater import app.revanced.patches.youtube.misc.playservice.is_19_49_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_30_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_34_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch -import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint import app.revanced.util.copyXmlNode import app.revanced.util.findElementByAttributeValueOrThrow @@ -43,56 +43,15 @@ import org.w3c.dom.Element import java.io.ByteArrayInputStream import kotlin.use -internal var reelTimeBarPlayedColorId = -1L - private set -internal var inlineTimeBarColorizedBarPlayedColorDarkId = -1L - private set -internal var inlineTimeBarPlayedNotHighlightedColorId = -1L - private set -internal var ytYoutubeMagentaColorId = -1L - private set -internal var ytStaticBrandRedId = -1L - private set -internal var ytTextSecondaryId = -1L - private set -internal var inlineTimeBarLiveSeekableRangeId = -1L - private set - -internal const val splashSeekbarColorAttributeName = "splash_custom_seekbar_color" +private const val splashSeekbarColorAttributeName = "splash_custom_seekbar_color" private val seekbarColorResourcePatch = resourcePatch { dependsOn( - settingsPatch, resourceMappingPatch, versionCheckPatch, ) execute { - reelTimeBarPlayedColorId = resourceMappings[ - "color", - "reel_time_bar_played_color", - ] - inlineTimeBarColorizedBarPlayedColorDarkId = resourceMappings[ - "color", - "inline_time_bar_colorized_bar_played_color_dark", - ] - inlineTimeBarPlayedNotHighlightedColorId = resourceMappings[ - "color", - "inline_time_bar_played_not_highlighted_color", - ] - ytStaticBrandRedId = resourceMappings[ - "attr", - "ytStaticBrandRed" - ] - ytTextSecondaryId = resourceMappings[ - "attr", - "ytTextSecondary" - ] - inlineTimeBarLiveSeekableRangeId = resourceMappings[ - "color", - "inline_time_bar_live_seekable_range" - ] - // Modify the resume playback drawable and replace the progress bar with a custom drawable. document("res/drawable/resume_playback_progressbar_drawable.xml").use { document -> val layerList = document.getElementsByTagName("layer-list").item(0) as Element @@ -113,15 +72,6 @@ private val seekbarColorResourcePatch = resourcePatch { return@execute } - ytYoutubeMagentaColorId = resourceMappings[ - "color", - "yt_youtube_magenta", - ] - ytStaticBrandRedId = resourceMappings[ - "attr", - "ytStaticBrandRed", - ] - // Add attribute and styles for splash screen custom color. // Using a style is the only way to selectively change just the seekbar fill color. // @@ -223,28 +173,31 @@ val seekbarColorPatch = bytecodePatch( sharedExtensionPatch, lithoColorHookPatch, seekbarColorResourcePatch, + resourceMappingPatch, versionCheckPatch ) execute { - fun MutableMethod.addColorChangeInstructions(resourceId: Long) { + fun MutableMethod.addColorChangeInstructions(index: Int) { insertLiteralOverride( - resourceId, + index, "$EXTENSION_CLASS_DESCRIPTOR->getVideoPlayerSeekbarColor(I)I" ) } - playerSeekbarColorFingerprint.method.apply { - addColorChangeInstructions(inlineTimeBarColorizedBarPlayedColorDarkId) - addColorChangeInstructions(inlineTimeBarPlayedNotHighlightedColorId) + playerSeekbarColorFingerprint.let { + it.method.apply { + addColorChangeInstructions(it.instructionMatches.last().index) + addColorChangeInstructions(it.instructionMatches.first().index) + } } - shortsSeekbarColorFingerprint.method.apply { - addColorChangeInstructions(reelTimeBarPlayedColorId) + shortsSeekbarColorFingerprint.let { + it.method.addColorChangeInstructions(it.instructionMatches.first().index) } setSeekbarClickedColorFingerprint.originalMethod.let { - val setColorMethodIndex = setSeekbarClickedColorFingerprint.patternMatch!!.startIndex + 1 + val setColorMethodIndex = setSeekbarClickedColorFingerprint.instructionMatches.first().index + 1 navigate(it).to(setColorMethodIndex).stop().apply { val colorRegister = getInstruction(0).registerA @@ -253,7 +206,7 @@ val seekbarColorPatch = bytecodePatch( """ invoke-static { v$colorRegister }, $EXTENSION_CLASS_DESCRIPTOR->getVideoPlayerSeekbarClickedColor(I)I move-result v$colorRegister - """, + """ ) } } @@ -266,32 +219,31 @@ val seekbarColorPatch = bytecodePatch( // 19.25+ changes - arrayOf( - playerSeekbarHandle1ColorFingerprint, - playerSeekbarHandle2ColorFingerprint - ).forEach { - it.method.addColorChangeInstructions(ytStaticBrandRedId) + var handleBarColorFingerprints = mutableListOf(playerSeekbarHandle1ColorFingerprint) + if (!is_20_34_or_greater) { + handleBarColorFingerprints += playerSeekbarHandle2ColorFingerprint + } + handleBarColorFingerprints.forEach { + it.method.addColorChangeInstructions(it.instructionMatches.last().index) } // If hiding feed seekbar thumbnails, then turn off the cairo gradient // of the watch history menu items as they use the same gradient as the // player and there is no easy way to distinguish which to use a transparent color. if (is_19_34_or_greater) { - watchHistoryMenuUseProgressDrawableFingerprint.method.apply { - val progressIndex = indexOfFirstInstructionOrThrow { - val reference = getReference() - reference?.definingClass == "Landroid/widget/ProgressBar;" && reference.name == "setMax" - } - val index = indexOfFirstInstructionOrThrow(progressIndex, Opcode.MOVE_RESULT) - val register = getInstruction(index).registerA + watchHistoryMenuUseProgressDrawableFingerprint.let { + it.method.apply { + val index = it.instructionMatches[1].index + val register = getInstruction(index).registerA - addInstructions( - index + 1, - """ - invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->showWatchHistoryProgressDrawable(Z)Z - move-result v$register - """ - ) + addInstructions( + index + 1, + """ + invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->showWatchHistoryProgressDrawable(Z)Z + move-result v$register + """ + ) + } } } @@ -315,7 +267,7 @@ val seekbarColorPatch = bytecodePatch( playerFingerprint.let { it.method.apply { - val index = it.patternMatch!!.endIndex + val index = it.instructionMatches.last().index val register = getInstruction(index).registerA addInstructions( @@ -347,7 +299,11 @@ val seekbarColorPatch = bytecodePatch( mainActivityOnCreateFingerprint ).forEach { fingerprint -> fingerprint.method.insertLiteralOverride( - launchScreenLayoutTypeLotteFeatureFlag, + if (is_20_30_or_greater) { + launchScreenLayoutTypeLotteFeatureFlag + } else { + launchScreenLayoutTypeLotteFeatureLegacyFlag + }, "$EXTENSION_CLASS_DESCRIPTOR->useLotteLaunchSplashScreen(Z)Z" ) } @@ -369,11 +325,12 @@ val seekbarColorPatch = bytecodePatch( ) // Replace the Lottie animation view setAnimation(int) call. - val setAnimationIntMethodName = lottieAnimationViewSetAnimationIntFingerprint.originalMethod.name + val setAnimationIntMethodName = + lottieAnimationViewSetAnimationIntFingerprint.originalMethod.name findInstructionIndicesReversedOrThrow { val reference = getReference() - reference?.definingClass == "Lcom/airbnb/lottie/LottieAnimationView;" + reference?.definingClass == LOTTIE_ANIMATION_VIEW_CLASS_TYPE && reference.name == setAnimationIntMethodName }.forEach { index -> val instruction = getInstruction(index) @@ -381,18 +338,18 @@ val seekbarColorPatch = bytecodePatch( replaceInstruction( index, "invoke-static { v${instruction.registerC}, v${instruction.registerD} }, " + - "$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie" + - "(Lcom/airbnb/lottie/LottieAnimationView;I)V" + "$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie" + + "(Lcom/airbnb/lottie/LottieAnimationView;I)V" ) } } - // Add non obfuscated method aliases for `setAnimation(int)` // and `setAnimation(InputStream, String)` so extension code can call them. lottieAnimationViewSetAnimationIntFingerprint.classDef.methods.apply { val addedMethodName = "patch_setAnimation" - val setAnimationIntName = lottieAnimationViewSetAnimationIntFingerprint.originalMethod.name + val setAnimationIntName = lottieAnimationViewSetAnimationIntFingerprint + .originalMethod.name add(ImmutableMethod( LOTTIE_ANIMATION_VIEW_CLASS_TYPE, @@ -412,9 +369,9 @@ val seekbarColorPatch = bytecodePatch( ) }) - val factoryStreamClass : CharSequence - val factoryStreamName : CharSequence - val factoryStreamReturnType : CharSequence + val factoryStreamClass: CharSequence + val factoryStreamName: CharSequence + val factoryStreamReturnType: CharSequence lottieCompositionFactoryFromJsonInputStreamFingerprint.match( lottieCompositionFactoryZipFingerprint.originalClassDef ).originalMethod.apply { @@ -423,6 +380,14 @@ val seekbarColorPatch = bytecodePatch( factoryStreamReturnType = returnType } + val lottieAnimationViewSetAnimationStreamFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + parameters(factoryStreamReturnType.toString()) + returns("V") + custom { _, classDef -> + classDef.type == lottieAnimationViewSetAnimationIntFingerprint.originalClassDef.type + } + } val setAnimationStreamName = lottieAnimationViewSetAnimationStreamFingerprint .originalMethod.name diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/Fingerprints.kt index 045d75ca2..c75606b95 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/Fingerprints.kt @@ -1,51 +1,50 @@ package app.revanced.patches.youtube.layout.shortsautoplay +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patcher.string 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.FieldReference -import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal val reelEnumConstructorFingerprint = fingerprint { +internal val reelEnumConstructorFingerprint by fingerprint { accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) - opcodes(Opcode.RETURN_VOID) - strings( - "REEL_LOOP_BEHAVIOR_UNKNOWN", - "REEL_LOOP_BEHAVIOR_SINGLE_PLAY", - "REEL_LOOP_BEHAVIOR_REPEAT", - "REEL_LOOP_BEHAVIOR_END_SCREEN", + instructions( + string("REEL_LOOP_BEHAVIOR_UNKNOWN"), + string("REEL_LOOP_BEHAVIOR_SINGLE_PLAY"), + string("REEL_LOOP_BEHAVIOR_REPEAT"), + string("REEL_LOOP_BEHAVIOR_END_SCREEN"), + opcode(Opcode.RETURN_VOID) ) } -internal val reelPlaybackRepeatFingerprint = fingerprint { +internal val reelPlaybackRepeatParentFingerprint by fingerprint { + returns("V") + parameters("Ljava/lang/String;", "J") + instructions( + string("Reels[%s] Playback Time: %d ms") + ) +} + +/** + * Matches class found in [reelPlaybackRepeatParentFingerprint]. + */ +internal val reelPlaybackRepeatFingerprint by fingerprint { returns("V") parameters("L") - strings("YoutubePlayerState is in throwing an Error.") + instructions( + methodCall(smali = "Lcom/google/common/util/concurrent/ListenableFuture;->isDone()Z") + ) } -internal val reelPlaybackFingerprint = fingerprint { +internal val reelPlaybackFingerprint by 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()?.name == "MILLISECONDS" - } - -internal fun indexOfInitializationInstruction(method: Method) = - method.indexOfFirstInstruction { - val reference = getReference() - opcode == Opcode.INVOKE_DIRECT && - reference?.name == "" && - reference.parameterTypes.size == 3 && - reference.parameterTypes.firstOrNull() == "I" - } + returns("V") + instructions( + fieldAccess(definingClass = "Ljava/util/concurrent/TimeUnit;", name = "MILLISECONDS"), + methodCall(name = "", parameters = listOf("I", "L", "L"), maxAfter = 15), + methodCall(opcode = Opcode.INVOKE_VIRTUAL, parameters = listOf("L"), returnType = "I", maxAfter = 5) + ) +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/ShortsAutoplayPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/ShortsAutoplayPatch.kt index 470bdc0b5..530c0ba06 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/ShortsAutoplayPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsautoplay/ShortsAutoplayPatch.kt @@ -72,23 +72,25 @@ val shortsAutoplayPatch = bytecodePatch( "invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->setMainActivity(Landroid/app/Activity;)V", ) - val reelEnumClass = reelEnumConstructorFingerprint.originalClassDef.type + var reelEnumClass : String - reelEnumConstructorFingerprint.method.apply { - val insertIndex = reelEnumConstructorFingerprint.patternMatch!!.startIndex + reelEnumConstructorFingerprint.let { + reelEnumClass = it.originalClassDef.type - addInstructions( - insertIndex, + it.method.addInstructions( + it.instructionMatches.last().index, """ # Pass the first enum value to extension. # Any enum value of this type will work. sget-object v0, $reelEnumClass->a:$reelEnumClass invoke-static { v0 }, $EXTENSION_CLASS_DESCRIPTOR->setYTShortsRepeatEnum(Ljava/lang/Enum;)V - """, + """ ) } - - reelPlaybackRepeatFingerprint.method.apply { + + reelPlaybackRepeatFingerprint.match( + reelPlaybackRepeatParentFingerprint.originalClassDef + ).method.apply { // The behavior enums are looked up from an ordinal value to an enum type. findInstructionIndicesReversedOrThrow { val reference = getReference() @@ -103,7 +105,7 @@ val shortsAutoplayPatch = bytecodePatch( """ invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->changeShortsRepeatBehavior(Ljava/lang/Enum;)Ljava/lang/Enum; move-result-object v$register - """, + """ ) } } @@ -112,13 +114,10 @@ val shortsAutoplayPatch = bytecodePatch( // 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(userActionMethodIndex).reference as MethodReference - val reelSequenceControllerMethodIndex = reelPlaybackFingerprint.method - .indexOfFirstInstructionOrThrow(userActionMethodIndex, Opcode.INVOKE_VIRTUAL) - val reelSequenceControllerMethodReference = reelPlaybackFingerprint.method - .getInstruction(reelSequenceControllerMethodIndex).reference as MethodReference + val userActionMethodReference = reelPlaybackFingerprint.instructionMatches[1] + .getInstruction().reference as MethodReference + val reelSequenceControllerMethodReference = reelPlaybackFingerprint.instructionMatches[2] + .getInstruction().reference as MethodReference reelPlaybackRepeatFingerprint.method.apply { // Find the first call modified by extension code above. @@ -127,7 +126,7 @@ val shortsAutoplayPatch = bytecodePatch( getReference()?.definingClass == EXTENSION_CLASS_DESCRIPTOR } + 1 val enumRegister = getInstruction(extensionReturnResultIndex).registerA - val getReelSequenceControllerIndex = indexOfFirstInstructionOrThrow(extensionReturnResultIndex) { + val getReelSequenceControllerIndex = indexOfFirstInstructionOrThrow { val reference = getReference() opcode == Opcode.IGET_OBJECT && reference?.definingClass == definingClass && diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsplayer/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsplayer/Fingerprints.kt index abd7f10ce..32228fa62 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsplayer/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsplayer/Fingerprints.kt @@ -1,25 +1,33 @@ package app.revanced.patches.youtube.layout.shortsplayer import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.string +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import com.android.tools.smali.dexlib2.AccessFlags /** * Purpose of this method is not clear, and it's only used to identify * the obfuscated name of the videoId() method in PlaybackStartDescriptor. */ -internal val playbackStartFeatureFlagFingerprint = fingerprint { +internal val playbackStartFeatureFlagFingerprint by fingerprint { returns("Z") parameters( "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;", ) - literal { - 45380134L - } + instructions( + methodCall( + definingClass = "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;", + returnType = "Ljava/lang/String;" + ), + literal(45380134L) + ) } // Pre 19.25 -internal val shortsPlaybackIntentLegacyFingerprint = fingerprint { +internal val shortsPlaybackIntentLegacyFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters( @@ -30,15 +38,16 @@ internal val shortsPlaybackIntentLegacyFingerprint = fingerprint { "Z", "Ljava/util/Map;" ) - strings( + instructions( + methodCall(returnType = "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"), // None of these strings are unique. - "com.google.android.apps.youtube.app.endpoint.flags", - "ReelWatchFragmentArgs", - "reels_fragment_descriptor" + string("com.google.android.apps.youtube.app.endpoint.flags"), + string("ReelWatchFragmentArgs"), + string("reels_fragment_descriptor") ) } -internal val shortsPlaybackIntentFingerprint = fingerprint { +internal val shortsPlaybackIntentFingerprint by fingerprint { accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL) returns("V") parameters( @@ -47,18 +56,18 @@ internal val shortsPlaybackIntentFingerprint = fingerprint { "J", "Ljava/lang/String;" ) - strings( + instructions( // None of these strings are unique. - "com.google.android.apps.youtube.app.endpoint.flags", - "ReelWatchFragmentArgs", - "reels_fragment_descriptor" + string("com.google.android.apps.youtube.app.endpoint.flags"), + string("ReelWatchFragmentArgs"), + string("reels_fragment_descriptor") ) } -internal val exitVideoPlayerFingerprint = fingerprint { +internal val exitVideoPlayerFingerprint by fingerprint { returns("V") parameters() - literal { - mdx_drawer_layout_id - } + instructions( + resourceLiteral(ResourceType.ID, "mdx_drawer_layout") + ) } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsplayer/OpenShortsInRegularPlayerPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsplayer/OpenShortsInRegularPlayerPatch.kt index 56abd43df..69169a0ff 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsplayer/OpenShortsInRegularPlayerPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/shortsplayer/OpenShortsInRegularPlayerPatch.kt @@ -5,18 +5,14 @@ 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.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.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.youtube.layout.player.fullscreen.openVideosFullscreenHookPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater -import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch @@ -32,21 +28,6 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/OpenShortsInRegularPlayerPatch;" -internal var mdx_drawer_layout_id = -1L - private set - -private val openShortsInRegularPlayerResourcePatch = resourcePatch { - dependsOn(resourceMappingPatch) - - execute { - mdx_drawer_layout_id = resourceMappings[ - "id", - "mdx_drawer_layout", - ] - - } -} - @Suppress("unused") val openShortsInRegularPlayerPatch = bytecodePatch( name = "Open Shorts in regular player", @@ -59,7 +40,7 @@ val openShortsInRegularPlayerPatch = bytecodePatch( openVideosFullscreenHookPatch, navigationBarHookPatch, versionCheckPatch, - openShortsInRegularPlayerResourcePatch + resourceMappingPatch ) compatibleWith( @@ -77,15 +58,7 @@ val openShortsInRegularPlayerPatch = bytecodePatch( addResources("youtube", "layout.shortsplayer.shortsPlayerTypePatch") PreferenceScreen.SHORTS.addPreferences( - if (is_19_46_or_greater) { - ListPreference("revanced_shorts_player_type") - } else { - ListPreference( - key = "revanced_shorts_player_type", - entriesKey = "revanced_shorts_player_type_legacy_entries", - entryValuesKey = "revanced_shorts_player_type_legacy_entry_values" - ) - } + ListPreference("revanced_shorts_player_type") ) // Activity is used as the context to launch an Intent. @@ -96,14 +69,11 @@ val openShortsInRegularPlayerPatch = bytecodePatch( ) // Find the obfuscated method name for PlaybackStartDescriptor.videoId() - val playbackStartVideoIdMethodName = playbackStartFeatureFlagFingerprint.method.let { - val stringMethodIndex = it.indexOfFirstInstructionOrThrow { - val reference = getReference() - reference?.definingClass == "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;" - && reference.returnType == "Ljava/lang/String;" + val playbackStartVideoIdMethodName = playbackStartFeatureFlagFingerprint.let { + val stringMethodIndex = it.instructionMatches.first().index + it.method.let { + navigate(it).to(stringMethodIndex).stop().name } - - navigate(it).to(stringMethodIndex).stop().name } fun extensionInstructions(playbackStartRegister: Int, freeRegister: Int) = @@ -119,33 +89,30 @@ val openShortsInRegularPlayerPatch = bytecodePatch( nop """ - if (!is_19_25_or_greater) { - shortsPlaybackIntentLegacyFingerprint.method.apply { - val index = indexOfFirstInstructionOrThrow { - getReference()?.returnType == - "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;" + if (is_19_25_or_greater) { + shortsPlaybackIntentFingerprint.method.addInstructionsWithLabels( + 0, + """ + move-object/from16 v0, p1 + ${extensionInstructions(0, 1)} + """ + ) + } else { + shortsPlaybackIntentLegacyFingerprint.let { + it.method.apply { + val index = it.instructionMatches.first().index + val playbackStartRegister = getInstruction(index + 1).registerA + val insertIndex = index + 2 + val freeRegister = findFreeRegister(insertIndex, playbackStartRegister) + + addInstructionsWithLabels( + insertIndex, + extensionInstructions(playbackStartRegister, freeRegister) + ) } - val playbackStartRegister = getInstruction(index + 1).registerA - val insertIndex = index + 2 - val freeRegister = findFreeRegister(insertIndex, playbackStartRegister) - - addInstructionsWithLabels( - insertIndex, - extensionInstructions(playbackStartRegister, freeRegister) - ) } - - return@execute } - shortsPlaybackIntentFingerprint.method.addInstructionsWithLabels( - 0, - """ - move-object/from16 v0, p1 - ${extensionInstructions(0, 1)} - """ - ) - // Fix issue with back button exiting the app instead of minimizing the player. // Without this change this issue can be difficult to reproduce, but seems to occur // most often with 'open video in regular player' and not open in fullscreen player. diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/Fingerprints.kt index dbbd0c000..d31d1cf9a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/Fingerprints.kt @@ -1,66 +1,52 @@ package app.revanced.patches.youtube.layout.sponsorblock +import app.revanced.patcher.checkCast import app.revanced.patcher.fingerprint +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral +import app.revanced.patches.youtube.shared.seekbarFingerprint import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionReversed 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.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal val appendTimeFingerprint = fingerprint { - returns("V") +internal val appendTimeFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") parameters("Ljava/lang/CharSequence;", "Ljava/lang/CharSequence;", "Ljava/lang/CharSequence;") - opcodes( - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.CHECK_CAST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT, + instructions( + resourceLiteral(ResourceType.STRING, "total_time"), + + methodCall(smali = "Landroid/content/res/Resources;->getString(I[Ljava/lang/Object;)Ljava/lang/String;"), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0) ) } -internal val controlsOverlayFingerprint = fingerprint { +internal val controlsOverlayFingerprint by fingerprint { returns("V") - accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) parameters() - opcodes( - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, // R.id.inset_overlay_view_layout - Opcode.IPUT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.NEW_INSTANCE, + instructions( + resourceLiteral(ResourceType.ID, "inset_overlay_view_layout"), + checkCast("Landroid/widget/FrameLayout;", maxAfter = 20) ) } -internal val rectangleFieldInvalidatorFingerprint = fingerprint { +/** + * Resolves to the class found in [seekbarFingerprint]. + */ +internal val rectangleFieldInvalidatorFingerprint by fingerprint { returns("V") - custom { method, _ -> - val instructions = method.implementation?.instructions!! - val instructionCount = instructions.count() - - // the method has definitely more than 5 instructions - if (instructionCount < 5) return@custom false - - val referenceInstruction = instructions.elementAt(instructionCount - 2) // the second to last instruction - val reference = ((referenceInstruction as? ReferenceInstruction)?.reference as? MethodReference) - - reference?.parameterTypes?.size == 1 && reference.name == "invalidate" // the reference is the invalidate(..) method - } + parameters() + instructions( + methodCall(name = "invalidate") + ) } -internal val adProgressTextViewVisibilityFingerprint = fingerprint { +internal val adProgressTextViewVisibilityFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Z") @@ -76,3 +62,4 @@ internal fun indexOfAdProgressTextViewVisibilityInstruction(method: Method) = "Lcom/google/android/libraries/youtube/ads/player/ui/AdProgressTextView;" && reference.name =="setVisibility" } + diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockPatch.kt index 80cbfe041..22068bf1a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockPatch.kt @@ -20,18 +20,24 @@ import app.revanced.patches.youtube.misc.playercontrols.* import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.patches.youtube.shared.* +import app.revanced.patches.youtube.shared.layoutConstructorFingerprint +import app.revanced.patches.youtube.shared.seekbarFingerprint +import app.revanced.patches.youtube.shared.seekbarOnDrawFingerprint import app.revanced.patches.youtube.video.information.onCreateHook import app.revanced.patches.youtube.video.information.videoInformationPatch import app.revanced.patches.youtube.video.information.videoTimeHook import app.revanced.patches.youtube.video.videoid.hookBackgroundPlayVideoId import app.revanced.patches.youtube.video.videoid.videoIdPatch -import app.revanced.util.* -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.* +import app.revanced.util.ResourceGroup +import app.revanced.util.addInstructionsAtControlFlowLabel +import app.revanced.util.copyResources +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionReversedOrThrow +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference -import com.android.tools.smali.dexlib2.iface.reference.StringReference private val sponsorBlockResourcePatch = resourcePatch { dependsOn( @@ -80,7 +86,6 @@ private val sponsorBlockResourcePatch = resourcePatch { "revanced_sb_skip_sponsor_button.xml", ), ResourceGroup( - // required resource for back button, because when the base APK is used, this resource will not exist "drawable", "revanced_sb_adjust.xml", "revanced_sb_backward.xml", @@ -99,7 +104,7 @@ private val sponsorBlockResourcePatch = resourcePatch { } } -private const val EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR = +internal const val EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/sponsorblock/SegmentPlaybackController;" private const val EXTENSION_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/sponsorblock/ui/CreateSegmentButton;" @@ -115,6 +120,7 @@ val sponsorBlockPatch = bytecodePatch( ) { dependsOn( sharedExtensionPatch, + resourceMappingPatch, videoIdPatch, // Required to skip segments on time. videoInformationPatch, @@ -147,42 +153,63 @@ val sponsorBlockPatch = bytecodePatch( "->setCurrentVideoId(Ljava/lang/String;)V", ) - // Seekbar drawing - seekbarOnDrawFingerprint.match(seekbarFingerprint.originalClassDef).method.apply { - // Get left and right of seekbar rectangle. - val moveRectangleToRegisterIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_OBJECT_FROM16) - - addInstruction( - moveRectangleToRegisterIndex + 1, - "invoke-static/range { p0 .. p0 }, " + - "$EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;)V", - ) - - // Set the thickness of the segment. - val thicknessIndex = indexOfFirstInstructionOrThrow { - opcode == Opcode.INVOKE_STATIC && getReference()?.name == "round" + // Set seekbar draw rectangle. + val rectangleFieldName: FieldReference + rectangleFieldInvalidatorFingerprint.match( + seekbarFingerprint.originalClassDef + ).let { + it.method.apply { + val rectangleIndex = indexOfFirstInstructionReversedOrThrow( + it.instructionMatches.first().index + ) { + getReference()?.type == "Landroid/graphics/Rect;" + } + rectangleFieldName = getInstruction(rectangleIndex).reference as FieldReference } - val thicknessRegister = getInstruction(thicknessIndex).registerC - addInstruction( - thicknessIndex + 2, - "invoke-static { v$thicknessRegister }, " + - "$EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarThickness(I)V", - ) + } - // Find the drawCircle call and draw the segment before it. - val drawCircleIndex = indexOfFirstInstructionReversedOrThrow { - getReference()?.name == "drawCircle" + // Seekbar drawing. + + // Shared fingerprint and indexes may have changed. + seekbarOnDrawFingerprint.clearMatch() + // Cannot match using original immutable class because + // class may have been modified by other patches + seekbarOnDrawFingerprint.match(seekbarFingerprint.classDef).let { + it.method.apply { + // Set seekbar thickness. + val thicknessIndex = it.instructionMatches.last().index + val thicknessRegister = getInstruction(thicknessIndex).registerA + addInstruction( + thicknessIndex + 1, + "invoke-static { v$thicknessRegister }, " + + "$EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSeekbarThickness(I)V", + ) + + // Find the drawCircle call and draw the segment before it. + val drawCircleIndex = indexOfFirstInstructionReversedOrThrow { + getReference()?.name == "drawCircle" + } + val drawCircleInstruction = getInstruction(drawCircleIndex) + val canvasInstanceRegister = drawCircleInstruction.registerC + val centerYRegister = drawCircleInstruction.registerE + + addInstruction( + drawCircleIndex, + "invoke-static { v$canvasInstanceRegister, v$centerYRegister }, " + + "$EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->" + + "drawSegmentTimeBars(Landroid/graphics/Canvas;F)V", + ) + + // Set seekbar bounds. + addInstructions( + 0, + """ + move-object/from16 v0, p0 + iget-object v0, v0, $rectangleFieldName + invoke-static { v0 }, $EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSeekbarRectangle(Landroid/graphics/Rect;)V + """ + ) } - val drawCircleInstruction = getInstruction(drawCircleIndex) - val canvasInstanceRegister = drawCircleInstruction.registerC - val centerYRegister = drawCircleInstruction.registerE - - addInstruction( - drawCircleIndex, - "invoke-static { v$canvasInstanceRegister, v$centerYRegister }, " + - "$EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->" + - "drawSponsorTimeBars(Landroid/graphics/Canvas;F)V", - ) } // Change visibility of the buttons. @@ -193,17 +220,19 @@ val sponsorBlockPatch = bytecodePatch( injectVisibilityCheckCall(EXTENSION_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR) // Append the new time to the player layout. - val appendTimePatternScanStartIndex = appendTimeFingerprint.patternMatch!!.startIndex - appendTimeFingerprint.method.apply { - val register = getInstruction(appendTimePatternScanStartIndex + 1).registerA + appendTimeFingerprint.let { + it.method.apply { + val index = it.instructionMatches.last().index + val register = getInstruction(index).registerA - addInstructions( - appendTimePatternScanStartIndex + 2, - """ - invoke-static { v$register }, $EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$register - """ - ) + addInstructions( + index + 1, + """ + invoke-static { v$register }, $EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$register + """ + ) + } } // Initialize the player controller. @@ -211,48 +240,16 @@ val sponsorBlockPatch = bytecodePatch( // Initialize the SponsorBlock view. controlsOverlayFingerprint.match(layoutConstructorFingerprint.originalClassDef).let { - val startIndex = it.patternMatch!!.startIndex + val checkCastIndex = it.instructionMatches.last().index it.method.apply { - val frameLayoutRegister = (getInstruction(startIndex + 2) as OneRegisterInstruction).registerA + val frameLayoutRegister = getInstruction(checkCastIndex).registerA addInstruction( - startIndex + 3, + checkCastIndex + 1, "invoke-static {v$frameLayoutRegister}, $EXTENSION_SPONSORBLOCK_VIEW_CONTROLLER_CLASS_DESCRIPTOR->initialize(Landroid/view/ViewGroup;)V", ) } } - // Set seekbar draw rectangle. - rectangleFieldInvalidatorFingerprint.match(seekbarOnDrawFingerprint.originalClassDef).method.apply { - val fieldIndex = instructions.count() - 3 - val fieldReference = getInstruction(fieldIndex).reference as FieldReference - - // replace the "replaceMeWith*" strings - proxy(classes.first { it.type.endsWith("SegmentPlaybackController;") }) - .mutableClass - .methods - .find { it.name == "setSponsorBarRect" } - ?.let { method -> - fun MutableMethod.replaceStringInstruction(index: Int, instruction: Instruction, with: String) { - val register = (instruction as OneRegisterInstruction).registerA - this.replaceInstruction( - index, - "const-string v$register, \"$with\"", - ) - } - for ((index, it) in method.instructions.withIndex()) { - if (it.opcode.ordinal != Opcode.CONST_STRING.ordinal) continue - - when (((it as ReferenceInstruction).reference as StringReference).string) { - "replaceMeWithsetSponsorBarRect" -> method.replaceStringInstruction( - index, - it, - fieldReference.name, - ) - } - } - } ?: throw PatchException("Could not find the method which contains the replaceMeWith* strings") - } - adProgressTextViewVisibilityFingerprint.method.apply { val index = indexOfAdProgressTextViewVisibilityInstruction(this) val register = getInstruction(index).registerD @@ -262,6 +259,5 @@ val sponsorBlockPatch = bytecodePatch( "invoke-static { v$register }, $EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setAdProgressTextVisibility(I)V" ) } - } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/Fingerprints.kt index ac458cec2..33c20c22f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/Fingerprints.kt @@ -1,31 +1,29 @@ package app.revanced.patches.youtube.layout.spoofappversion +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint -import app.revanced.util.containsLiteralInstruction -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral 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 toolBarButtonFingerprint = fingerprint { +internal val toolBarButtonFingerprint by fingerprint { returns("V") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters("Landroid/view/MenuItem;") - custom { method, _ -> - method.containsLiteralInstruction(menuItemView) && - indexOfGetDrawableInstruction(method) >= 0 - } + instructions( + resourceLiteral(ResourceType.ID, "menu_item_view"), + methodCall(returnType = "I", opcode = Opcode.INVOKE_INTERFACE), + opcode(Opcode.MOVE_RESULT, maxAfter = 0), // Value is zero if resource does not exist. + fieldAccess(type = "Landroid/widget/ImageView;", opcode = Opcode.IGET_OBJECT, maxAfter = 6), + methodCall("Landroid/content/res/Resources;", "getDrawable", maxAfter = 8), + methodCall("Landroid/widget/ImageView;", "setImageDrawable", maxAfter = 4) + ) } -internal fun indexOfGetDrawableInstruction(method: Method) = method.indexOfFirstInstruction { - val reference = getReference() - reference?.definingClass == "Landroid/content/res/Resources;" && - reference.name == "getDrawable" -} - -internal val spoofAppVersionFingerprint = fingerprint { +internal val spoofAppVersionFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("L") parameters("L") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt index 0d6b6c89c..e4482be7f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt @@ -4,13 +4,10 @@ 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.patch.bytecodePatch -import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.util.smali.ExternalLabel 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.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting @@ -20,25 +17,7 @@ import app.revanced.patches.youtube.misc.playservice.is_19_43_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.indexOfFirstInstructionReversedOrThrow -import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.reference.MethodReference - -internal var menuItemView = -1L - private set - -internal val spoofAppVersionResourcePatch = resourcePatch { - dependsOn( - resourceMappingPatch - ) - - execute { - menuItemView = resourceMappings["id", "menu_item_view"] - } -} private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/spoof/SpoofAppVersionPatch;" @@ -49,7 +28,7 @@ val spoofAppVersionPatch = bytecodePatch( "This can be used to restore old UI elements and features." ) { dependsOn( - spoofAppVersionResourcePatch, + resourceMappingPatch, sharedExtensionPatch, settingsPatch, addResourcesPatch, @@ -80,14 +59,10 @@ val spoofAppVersionPatch = bytecodePatch( preferences = setOf( SwitchPreference("revanced_spoof_app_version"), if (is_19_43_or_greater) { - ListPreference( - key = "revanced_spoof_app_version_target", - summaryKey = null - ) + ListPreference("revanced_spoof_app_version_target") } else { ListPreference( key = "revanced_spoof_app_version_target", - summaryKey = null, entriesKey = "revanced_spoof_app_version_target_legacy_entries", entryValuesKey = "revanced_spoof_app_version_target_legacy_entry_values" ) @@ -101,35 +76,27 @@ val spoofAppVersionPatch = bytecodePatch( * missing image resources. As a workaround, do not set an image in the * toolbar when the enum name is UNKNOWN. */ - toolBarButtonFingerprint.method.apply { - val getDrawableIndex = indexOfGetDrawableInstruction(this) - val enumOrdinalIndex = indexOfFirstInstructionReversedOrThrow(getDrawableIndex) { - opcode == Opcode.INVOKE_INTERFACE && - getReference()?.returnType == "I" - } - val insertIndex = enumOrdinalIndex + 2 - val insertRegister = getInstruction(insertIndex - 1).registerA - val jumpIndex = indexOfFirstInstructionOrThrow(insertIndex) { - opcode == Opcode.INVOKE_VIRTUAL && - getReference()?.name == "setImageDrawable" - } + 1 + toolBarButtonFingerprint.apply { + val imageResourceIndex = instructionMatches[2].index + val register = method.getInstruction(imageResourceIndex).registerA + val jumpIndex = instructionMatches.last().index + 1 - addInstructionsWithLabels( - insertIndex, - "if-eqz v$insertRegister, :ignore", - ExternalLabel("ignore", getInstruction(jumpIndex)) + method.addInstructionsWithLabels( + imageResourceIndex + 1, + "if-eqz v$register, :ignore", + ExternalLabel("ignore", method.getInstruction(jumpIndex)) ) } spoofAppVersionFingerprint.apply { - val startIndex = patternMatch!!.startIndex - val buildOverrideNameRegister = method.getInstruction(startIndex).registerA + val index = instructionMatches.first().index + val register = method.getInstruction(index).registerA method.addInstructions( - startIndex + 1, + index + 1, """ - invoke-static {v$buildOverrideNameRegister}, $EXTENSION_CLASS_DESCRIPTOR->getYouTubeVersionOverride(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$buildOverrideNameRegister + invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getYouTubeVersionOverride(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$register """ ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt index e54d13e79..91eee1b75 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt @@ -60,19 +60,19 @@ val changeStartPagePatch = bytecodePatch( ) // Hook browseId. - browseIdFingerprint.method.apply { - val browseIdIndex = indexOfFirstInstructionOrThrow { - getReference()?.string == "FEwhat_to_watch" - } - val browseIdRegister = getInstruction(browseIdIndex).registerA + browseIdFingerprint.let { + it.method.apply { + val browseIdIndex = it.instructionMatches.first().index + val browseIdRegister = getInstruction(browseIdIndex).registerA - addInstructions( - browseIdIndex + 1, - """ - invoke-static { v$browseIdRegister }, $EXTENSION_CLASS_DESCRIPTOR->overrideBrowseId(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$browseIdRegister - """, - ) + addInstructions( + browseIdIndex + 1, + """ + invoke-static { v$browseIdRegister }, $EXTENSION_CLASS_DESCRIPTOR->overrideBrowseId(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$browseIdRegister + """ + ) + } } // There is no browserId assigned to Shorts and Search. diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/Fingerprints.kt index 022084020..f25f04cd6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/Fingerprints.kt @@ -1,20 +1,25 @@ package app.revanced.patches.youtube.layout.startpage +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint +import app.revanced.patcher.literal +import app.revanced.patcher.string import com.android.tools.smali.dexlib2.Opcode -internal val intentActionFingerprint = fingerprint { +internal val intentActionFingerprint by fingerprint { parameters("Landroid/content/Intent;") - strings("has_handled_intent") + instructions( + string("has_handled_intent") + ) } -internal val browseIdFingerprint = fingerprint { +internal val browseIdFingerprint by fingerprint { returns("Lcom/google/android/apps/youtube/app/common/ui/navigation/PaneDescriptor;") - parameters() - opcodes( - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.RETURN_OBJECT, + + //parameters() // 20.30 and earlier is no parameters. 20.31+ parameter is L. + instructions( + string("FEwhat_to_watch"), + literal(512), + fieldAccess(opcode = Opcode.IPUT_OBJECT, type = "Ljava/lang/String;") ) - strings("FEwhat_to_watch") } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt index 4a8737fa4..0c3b4099e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt @@ -1,20 +1,19 @@ package app.revanced.patches.youtube.layout.startupshortsreset import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch -import app.revanced.patches.youtube.misc.playservice.is_20_02_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_03_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.util.addInstructionsAtControlFlowLabel import app.revanced.util.findFreeRegister import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.indexOfFirstInstructionReversedOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference @@ -30,6 +29,7 @@ val disableResumingShortsOnStartupPatch = bytecodePatch( sharedExtensionPatch, settingsPatch, addResourcesPatch, + versionCheckPatch ) compatibleWith( @@ -50,45 +50,41 @@ val disableResumingShortsOnStartupPatch = bytecodePatch( SwitchPreference("revanced_disable_resuming_shorts_player"), ) - if (is_20_02_or_greater) { + if (is_20_03_or_greater) { userWasInShortsAlternativeFingerprint.let { it.method.apply { - val stringIndex = it.stringMatches!!.first().index - val booleanValueIndex = indexOfFirstInstructionReversedOrThrow(stringIndex) { - opcode == Opcode.INVOKE_VIRTUAL && - getReference()?.name == "booleanValue" - } - val booleanValueRegister = - getInstruction(booleanValueIndex + 1).registerA + val match = it.instructionMatches[2] + val insertIndex = match.index + 1 + val register = match.getInstruction().registerA addInstructions( - booleanValueIndex + 2, """ - invoke-static {v$booleanValueRegister}, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer(Z)Z - move-result v$booleanValueRegister - """ + insertIndex, + """ + invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer(Z)Z + move-result v$register + """ ) } } } else { userWasInShortsLegacyFingerprint.method.apply { val listenableInstructionIndex = indexOfFirstInstructionOrThrow { - val reference = getReference() opcode == Opcode.INVOKE_INTERFACE && - reference?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" && - reference.name == "isDone" + getReference()?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" && + getReference()?.name == "isDone" } val freeRegister = findFreeRegister(listenableInstructionIndex) addInstructionsAtControlFlowLabel( listenableInstructionIndex, """ - invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z + invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z move-result v$freeRegister - if-eqz v$freeRegister, :show + if-eqz v$freeRegister, :show_startup_shorts_player return-void - :show + :show_startup_shorts_player nop - """ + """, ) } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/Fingerprints.kt index b1fab6fcb..d66851054 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/Fingerprints.kt @@ -1,33 +1,49 @@ package app.revanced.patches.youtube.layout.startupshortsreset +import app.revanced.patcher.checkCast import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patcher.string import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode /** - * YouTube 20.02.08 ~ + * 20.02+ */ -internal val userWasInShortsAlternativeFingerprint = fingerprint { +internal val userWasInShortsAlternativeFingerprint by fingerprint { returns("V") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters("Ljava/lang/Object;") - strings("userIsInShorts: ") + instructions( + checkCast("Ljava/lang/Boolean;"), + methodCall(smali = "Ljava/lang/Boolean;->booleanValue()Z", maxAfter = 0), + opcode(Opcode.MOVE_RESULT, maxAfter = 0), + string("userIsInShorts: ", maxAfter = 5) + ) } -internal val userWasInShortsLegacyFingerprint = fingerprint { +/** + * Pre 20.02 + */ +internal val userWasInShortsLegacyFingerprint by fingerprint { returns("V") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) parameters("Ljava/lang/Object;") - strings("Failed to read user_was_in_shorts proto after successful warmup") + instructions( + string("Failed to read user_was_in_shorts proto after successful warmup") + ) } /** * 18.15.40+ */ -internal val userWasInShortsConfigFingerprint = fingerprint { +internal val userWasInShortsConfigFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") - literal { - 45358360L - } + parameters() + instructions( + literal(45358360L) + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt deleted file mode 100644 index c04f5e99c..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.layout.tablet - -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.youtube.layout.formfactor.changeFormFactorPatch - -@Deprecated("Use 'Change form factor' instead.") -val enableTabletLayoutPatch = bytecodePatch { - dependsOn(changeFormFactorPatch) -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/Fingerprints.kt index 8864c20c6..b8c54dad8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/Fingerprints.kt @@ -1,41 +1,62 @@ package app.revanced.patches.youtube.layout.theme +import app.revanced.patcher.anyInstruction +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val lithoThemeFingerprint = fingerprint { +internal val lithoThemeFingerprint by fingerprint { accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL) returns("V") parameters("Landroid/graphics/Rect;") - opcodes( - Opcode.IGET, - Opcode.IF_EQZ, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_NEZ, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.RETURN_VOID, + instructions( + fieldAccess( + opcode = Opcode.IPUT_OBJECT, + definingClass = "this", + type = "Landroid/graphics/Path;" + ), + + methodCall( + definingClass = "this", + name = "isStateful", + returnType = "Z", + maxAfter = 5 + ), + + fieldAccess( + opcode = Opcode.IGET_OBJECT, + definingClass = "this", + type = "Landroid/graphics/Paint", + maxAfter = 5 + ), + methodCall( + smali = "Landroid/graphics/Paint;->setColor(I)V", + maxAfter = 0 + ) ) custom { method, _ -> method.name == "onBoundsChange" } } -internal const val GRADIENT_LOADING_SCREEN_AB_CONSTANT = 45412406L - -internal val useGradientLoadingScreenFingerprint = fingerprint { - literal { GRADIENT_LOADING_SCREEN_AB_CONSTANT } +internal val useGradientLoadingScreenFingerprint by fingerprint { + instructions( + literal(45412406L) + ) } -internal const val SPLASH_SCREEN_STYLE_FEATURE_FLAG = 269032877L - -internal val splashScreenStyleFingerprint = fingerprint { +internal val splashScreenStyleFingerprint by fingerprint { returns("V") parameters("Landroid/os/Bundle;") - literal { SPLASH_SCREEN_STYLE_FEATURE_FLAG } + instructions( + anyInstruction( + literal(1074339245), // 20.30+ + literal(269032877L) // 20.29 and lower. + ) + ) custom { method, classDef -> method.name == "onCreate" && classDef.endsWith("/MainActivity;") } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/LithoColorHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/LithoColorHookPatch.kt index fdab6c4b8..6ca91d1e9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/LithoColorHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/LithoColorHookPatch.kt @@ -3,6 +3,9 @@ package app.revanced.patches.youtube.layout.theme import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.patch.bytecodePatch +/** + * Hooks most color usage of litho components. + */ lateinit var lithoColorOverrideHook: (targetMethodClass: String, targetMethodName: String) -> Unit private set @@ -11,8 +14,7 @@ val lithoColorHookPatch = bytecodePatch( ) { execute { - - var insertionIndex = lithoThemeFingerprint.patternMatch!!.endIndex - 1 + var insertionIndex = lithoThemeFingerprint.instructionMatches.last().index lithoColorOverrideHook = { targetMethodClass, targetMethodName -> lithoThemeFingerprint.method.addInstructions( @@ -20,7 +22,7 @@ val lithoColorHookPatch = bytecodePatch( """ invoke-static { p1 }, $targetMethodClass->$targetMethodName(I)I move-result p1 - """, + """ ) insertionIndex += 2 } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt index 04d7a3d79..26488779a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemePatch.kt @@ -173,7 +173,7 @@ val themePatch = bytecodePatch( // Fix the splash screen dark mode background color. // In 19.32+ the dark mode splash screen is white and fades to black. // Maybe it's a bug in YT, or maybe it intentionally. Who knows. - document("res/values-night-v27/styles.xml").use { document -> + document("res/values-night/styles.xml").use { document -> // Create a night mode specific override for the splash screen background. val style = document.createElement("style") style.setAttribute("name", "Theme.YouTube.Home") @@ -226,17 +226,21 @@ val themePatch = bytecodePatch( ) } - useGradientLoadingScreenFingerprint.method.insertLiteralOverride( - GRADIENT_LOADING_SCREEN_AB_CONSTANT, - "$EXTENSION_CLASS_DESCRIPTOR->gradientLoadingScreenEnabled(Z)Z" - ) + useGradientLoadingScreenFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->gradientLoadingScreenEnabled(Z)Z" + ) + } if (is_19_47_or_greater) { // Lottie splash screen exists in earlier versions, but it may not be always on. - splashScreenStyleFingerprint.method.insertLiteralOverride( - SPLASH_SCREEN_STYLE_FEATURE_FLAG, - "$EXTENSION_CLASS_DESCRIPTOR->getLoadingScreenType(I)I" - ) + splashScreenStyleFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + "$EXTENSION_CLASS_DESCRIPTOR->getLoadingScreenType(I)I" + ) + } } lithoColorOverrideHook(EXTENSION_CLASS_DESCRIPTOR, "getValue") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt index a0e44d4d5..c1c920767 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch.kt @@ -3,12 +3,11 @@ package app.revanced.patches.youtube.misc.backgroundplayback import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.instructions 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.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch @@ -25,14 +24,6 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference internal var prefBackgroundAndOfflineCategoryId = -1L private set -private val backgroundPlaybackResourcePatch = resourcePatch { - dependsOn(resourceMappingPatch, addResourcesPatch) - - execute { - prefBackgroundAndOfflineCategoryId = resourceMappings["string", "pref_background_and_offline_category"] - } -} - private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/BackgroundPlaybackPatch;" @@ -41,7 +32,8 @@ val backgroundPlaybackPatch = bytecodePatch( description = "Removes restrictions on background playback, including playing kids videos in the background.", ) { dependsOn( - backgroundPlaybackResourcePatch, + resourceMappingPatch, + addResourcesPatch, sharedExtensionPatch, playerTypeHookPatch, videoInformationPatch, @@ -64,7 +56,12 @@ val backgroundPlaybackPatch = bytecodePatch( addResources("youtube", "misc.backgroundplayback.backgroundPlaybackPatch") PreferenceScreen.SHORTS.addPreferences( - SwitchPreference("revanced_shorts_disable_background_playback"), + SwitchPreference("revanced_shorts_disable_background_playback") + ) + + prefBackgroundAndOfflineCategoryId = getResourceId( + ResourceType.STRING, + "pref_background_and_offline_category" ) arrayOf( @@ -106,10 +103,12 @@ val backgroundPlaybackPatch = bytecodePatch( // Fix PiP buttons not working after locking/unlocking device screen. if (is_19_34_or_greater) { - pipInputConsumerFeatureFlagFingerprint.method.insertLiteralOverride( - PIP_INPUT_CONSUMER_FEATURE_FLAG, - false - ) + pipInputConsumerFeatureFlagFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + false + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt index a5c077115..23a6903bc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/backgroundplayback/Fingerprints.kt @@ -5,7 +5,7 @@ import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val backgroundPlaybackManagerFingerprint = fingerprint { +internal val backgroundPlaybackManagerFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Z") parameters("L") @@ -38,7 +38,7 @@ internal val backgroundPlaybackManagerFingerprint = fingerprint { ) } -internal val backgroundPlaybackSettingsFingerprint = fingerprint { +internal val backgroundPlaybackSettingsFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/String;") parameters() @@ -54,7 +54,7 @@ internal val backgroundPlaybackSettingsFingerprint = fingerprint { literal { prefBackgroundAndOfflineCategoryId } } -internal val kidsBackgroundPlaybackPolicyControllerFingerprint = fingerprint { +internal val kidsBackgroundPlaybackPolicyControllerFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("I", "L", "L") @@ -71,23 +71,28 @@ internal val kidsBackgroundPlaybackPolicyControllerFingerprint = fingerprint { literal { 5 } } -internal val backgroundPlaybackManagerShortsFingerprint = fingerprint { +internal val backgroundPlaybackManagerShortsFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Z") parameters("L") - literal { 151635310 } + instructions( + app.revanced.patcher.literal(151635310) + ) } -internal val shortsBackgroundPlaybackFeatureFlagFingerprint = fingerprint { +internal val shortsBackgroundPlaybackFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() - literal { 45415425 } + instructions( + app.revanced.patcher.literal(45415425) + ) } -internal const val PIP_INPUT_CONSUMER_FEATURE_FLAG = 45638483L - // Fix 'E/InputDispatcher: Window handle pip_input_consumer has no registered input channel' -internal val pipInputConsumerFeatureFlagFingerprint = fingerprint { - literal { PIP_INPUT_CONSUMER_FEATURE_FLAG} +internal val pipInputConsumerFeatureFlagFingerprint by fingerprint { + instructions( + // PiP input consumer feature flag. + app.revanced.patcher.literal(45638483L) + ) } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/Fingerprints.kt index 33e188974..03ba7a99b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/Fingerprints.kt @@ -1,34 +1,37 @@ package app.revanced.patches.youtube.misc.debugging import app.revanced.patcher.fingerprint +import app.revanced.patcher.string import com.android.tools.smali.dexlib2.AccessFlags -internal val experimentalFeatureFlagParentFingerprint = fingerprint { +internal val experimentalFeatureFlagParentFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("L") parameters("L", "J", "[B") - strings("Unable to parse proto typed experiment flag: ") + instructions( + string("Unable to parse proto typed experiment flag: ") + ) } -internal val experimentalBooleanFeatureFlagFingerprint = fingerprint { +internal val experimentalBooleanFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Z") parameters("L", "J", "Z") } -internal val experimentalDoubleFeatureFlagFingerprint = fingerprint { +internal val experimentalDoubleFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("D") parameters("J", "D") } -internal val experimentalLongFeatureFlagFingerprint = fingerprint { +internal val experimentalLongFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("J") parameters("J", "J") } -internal val experimentalStringFeatureFlagFingerprint = fingerprint { +internal val experimentalStringFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/String;") parameters("J", "Ljava/lang/String;") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/Fingerprints.kt index 4f99a4cf5..6d772c516 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/Fingerprints.kt @@ -1,8 +1,12 @@ package app.revanced.patches.youtube.misc.dimensions.spoof import app.revanced.patcher.fingerprint +import app.revanced.patcher.string -internal val deviceDimensionsModelToStringFingerprint = fingerprint { +internal val deviceDimensionsModelToStringFingerprint by fingerprint { returns("L") - strings("minh.", ";maxh.") + instructions( + string("minh."), + string(";maxh.") + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt index 5de171637..53ab2e832 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt @@ -45,7 +45,7 @@ val spoofDeviceDimensionsPatch = bytecodePatch( // Override the parameters containing the dimensions. .addInstructions( 1, // Add after super call. - mapOf( + arrayOf( 1 to "MinHeightOrWidth", // p1 = min height 2 to "MaxHeightOrWidth", // p2 = max height 3 to "MinHeightOrWidth", // p3 = min width diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/extension/hooks/ApplicationInitHook.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/extension/hooks/ApplicationInitHook.kt index 6a0e7d1f4..8f2274d83 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/extension/hooks/ApplicationInitHook.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/extension/hooks/ApplicationInitHook.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.misc.extension.hooks +import app.revanced.patcher.string import app.revanced.patches.shared.misc.extension.extensionHook /** @@ -7,5 +8,8 @@ import app.revanced.patches.shared.misc.extension.extensionHook */ // Extension context is the Activity itself. internal val applicationInitHook = extensionHook { - strings("Application creation", "Application.onCreate") + instructions( + string("Application.onCreate"), + string("Application creation") + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/Fingerprints.kt index 3de2e836a..3fb5562a8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/Fingerprints.kt @@ -1,10 +1,14 @@ package app.revanced.patches.youtube.misc.fix.backtoexitgesture -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.AccessFlags +import app.revanced.patcher.checkCast import app.revanced.patcher.fingerprint +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode -internal val scrollPositionFingerprint = fingerprint { +internal val scrollPositionFingerprint by fingerprint { accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL) returns("V") parameters("L") @@ -16,44 +20,16 @@ internal val scrollPositionFingerprint = fingerprint { strings("scroll_position") } -/** - * Resolves using class found in [recyclerViewTopScrollingParentFingerprint]. - */ -internal val recyclerViewTopScrollingFingerprint = fingerprint { +internal val recyclerViewTopScrollingFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters() - opcodes( - Opcode.IGET_OBJECT, - Opcode.IF_EQZ, - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.CONST_4, - Opcode.INVOKE_VIRTUAL, - Opcode.GOTO, - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - ) -} - -internal val recyclerViewTopScrollingParentFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - parameters("L", "L", "Landroid/view/ViewGroup;", "Landroid/view/ViewGroup;") - opcodes( - Opcode.INVOKE_DIRECT, - Opcode.IPUT_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.CONST_16, - Opcode.INVOKE_VIRTUAL, - Opcode.NEW_INSTANCE, + instructions( + methodCall(smali = "Ljava/util/Iterator;->next()Ljava/lang/Object;"), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0), + checkCast("Landroid/support/v7/widget/RecyclerView;", maxAfter = 0), + literal(0, maxAfter = 0), + methodCall(definingClass = "Landroid/support/v7/widget/RecyclerView;", maxAfter = 0), + opcode(Opcode.GOTO, maxAfter = 0) ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/FixBackToExitGesturePatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/FixBackToExitGesturePatch.kt index d64857769..f299aab38 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/FixBackToExitGesturePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/FixBackToExitGesturePatch.kt @@ -3,6 +3,7 @@ package app.revanced.patches.youtube.misc.fix.backtoexitgesture import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.youtube.shared.mainActivityOnBackPressedFingerprint +import app.revanced.util.addInstructionsAtControlFlowLabel import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow import com.android.tools.smali.dexlib2.Opcode @@ -15,17 +16,16 @@ internal val fixBackToExitGesturePatch = bytecodePatch( ) { execute { - recyclerViewTopScrollingFingerprint.match(recyclerViewTopScrollingParentFingerprint.originalClassDef) - .let { - it.method.addInstruction( - it.patternMatch!!.endIndex, - "invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->onTopView()V" - ) - } + recyclerViewTopScrollingFingerprint.let { + it.method.addInstructionsAtControlFlowLabel( + it.instructionMatches.last().index + 1, + "invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->onTopView()V" + ) + } scrollPositionFingerprint.let { navigate(it.originalMethod) - .to(it.patternMatch!!.startIndex + 1) + .to(it.instructionMatches.first().index + 1) .stop().apply { val index = indexOfFirstInstructionOrThrow { opcode == Opcode.INVOKE_VIRTUAL && getReference()?.definingClass == diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt deleted file mode 100644 index 89e7cc08f..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback - -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated("Use app.revanced.patches.youtube.misc.spoof.spoofVideoStreamsPatch instead.") -@Suppress("unused") -val spoofVideoStreamsPatch = bytecodePatch { - dependsOn(app.revanced.patches.youtube.misc.spoof.spoofVideoStreamsPatch) -} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch.kt deleted file mode 100644 index eb4c9492b..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback - -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated("Use app.revanced.patches.youtube.misc.spoof.userAgentClientSpoofPatch instead.") -@Suppress("unused") -val userAgentClientSpoofPatch = bytecodePatch { - dependsOn(app.revanced.patches.youtube.misc.spoof.userAgentClientSpoofPatch) -} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/Fingerprints.kt index d5a255ca5..9ae70b23b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playbackspeed/Fingerprints.kt @@ -12,7 +12,7 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference * This method is usually used to set the initial speed (1.0x) when playback starts from the feed. * For some reason, in the latest YouTube, it is invoked even after the video has already started. */ -internal val playbackSpeedInFeedsFingerprint = fingerprint { +internal val playbackSpeedInFeedsFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/AccountCredentialsInvalidTextPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/AccountCredentialsInvalidTextPatch.kt index 673fa240a..93e912add 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/AccountCredentialsInvalidTextPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/AccountCredentialsInvalidTextPatch.kt @@ -3,44 +3,17 @@ 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 ) @@ -60,18 +33,12 @@ internal val accountCredentialsInvalidTextPatch = bytecodePatch { 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() - reference?.name == "getString" - } - val register = getInstruction(getStringIndex + 1).registerA + fingerprint.apply { + val index = instructionMatches.last().index + val register = method.getInstruction(index).registerA - addInstructions( - getStringIndex + 2, + method.addInstructions( + index + 1, """ invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getOfflineNetworkErrorString(Ljava/lang/String;)Ljava/lang/String; move-result-object v$register diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/Fingerprints.kt index 3f4a521df..8fe2e05a5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/gms/Fingerprints.kt @@ -1,27 +1,35 @@ package app.revanced.patches.youtube.misc.gms import app.revanced.patcher.fingerprint -import app.revanced.util.containsLiteralInstruction +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode -internal val specificNetworkErrorViewControllerFingerprint = fingerprint { +internal val specificNetworkErrorViewControllerFingerprint by 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) - } + instructions( + resourceLiteral(ResourceType.DRAWABLE, "ic_offline_no_content_upside_down"), + resourceLiteral(ResourceType.STRING, "offline_no_content_body_text_not_offline_eligible"), + methodCall(name = "getString", returnType = "Ljava/lang/String;"), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0) + ) } // 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 { +internal val loadingFrameLayoutControllerFingerprint by 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) - } + instructions( + resourceLiteral(ResourceType.DRAWABLE, "ic_offline_no_content_upside_down"), + resourceLiteral(ResourceType.STRING, "offline_no_content_body_text_not_offline_eligible"), + methodCall(name = "getString", returnType = "Ljava/lang/String;"), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0) + ) } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/hapticfeedback/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/hapticfeedback/Fingerprints.kt index 13efc4693..d556efa94 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/hapticfeedback/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/hapticfeedback/Fingerprints.kt @@ -2,22 +2,22 @@ package app.revanced.patches.youtube.misc.hapticfeedback import app.revanced.patcher.fingerprint -internal val markerHapticsFingerprint = fingerprint { +internal val markerHapticsFingerprint by fingerprint { returns("V") strings("Failed to execute markers haptics vibrate.") } -internal val scrubbingHapticsFingerprint = fingerprint { +internal val scrubbingHapticsFingerprint by fingerprint { returns("V") strings("Failed to haptics vibrate for fine scrubbing.") } -internal val seekUndoHapticsFingerprint = fingerprint { +internal val seekUndoHapticsFingerprint by fingerprint { returns("V") strings("Failed to execute seek undo haptics vibrate.") } -internal val zoomHapticsFingerprint = fingerprint { +internal val zoomHapticsFingerprint by fingerprint { returns("V") strings("Failed to haptics vibrate for video zoom") } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/imageurlhook/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/imageurlhook/Fingerprints.kt index fcd5298ac..52315bc69 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/imageurlhook/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/imageurlhook/Fingerprints.kt @@ -1,9 +1,10 @@ package app.revanced.patches.youtube.misc.imageurlhook import app.revanced.patcher.fingerprint +import app.revanced.patcher.string import com.android.tools.smali.dexlib2.AccessFlags -internal val onFailureFingerprint = fingerprint { +internal val onFailureFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters( @@ -17,7 +18,7 @@ internal val onFailureFingerprint = fingerprint { } // Acts as a parent fingerprint. -internal val onResponseStartedFingerprint = fingerprint { +internal val onResponseStartedFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Lorg/chromium/net/UrlRequest;", "Lorg/chromium/net/UrlResponseInfo;") @@ -32,7 +33,7 @@ internal val onResponseStartedFingerprint = fingerprint { } } -internal val onSucceededFingerprint = fingerprint { +internal val onSucceededFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Lorg/chromium/net/UrlRequest;", "Lorg/chromium/net/UrlResponseInfo;") @@ -43,22 +44,23 @@ internal val onSucceededFingerprint = fingerprint { internal const val CRONET_URL_REQUEST_CLASS_DESCRIPTOR = "Lorg/chromium/net/impl/CronetUrlRequest;" -internal val requestFingerprint = fingerprint { +internal val requestFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") custom { _, classDef -> classDef.type == CRONET_URL_REQUEST_CLASS_DESCRIPTOR } } -internal val messageDigestImageUrlFingerprint = fingerprint { +internal val messageDigestImageUrlFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameters("Ljava/lang/String;", "L") } -internal val messageDigestImageUrlParentFingerprint = fingerprint { +internal val messageDigestImageUrlParentFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/String;") parameters() - strings("@#&=*+-_.,:!?()/~'%;\$") + instructions( + string("@#&=*+-_.,:!?()/~'%;\$"), + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt index 6f0b94ece..23025d176 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt @@ -7,17 +7,11 @@ import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch -import app.revanced.patches.youtube.misc.playservice.is_19_33_or_greater -import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction -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.reference.MethodReference -import com.android.tools.smali.dexlib2.iface.reference.TypeReference + +private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/BypassURLRedirectsPatch;" val bypassURLRedirectsPatch = bytecodePatch( name = "Bypass URL redirects", @@ -27,7 +21,6 @@ val bypassURLRedirectsPatch = bytecodePatch( sharedExtensionPatch, settingsPatch, addResourcesPatch, - versionCheckPatch, ) compatibleWith( @@ -48,41 +41,20 @@ val bypassURLRedirectsPatch = bytecodePatch( SwitchPreference("revanced_bypass_url_redirects"), ) - val fingerprints = if (is_19_33_or_greater) { - arrayOf( - abUriParserFingerprint, - httpUriParserFingerprint, - ) - } else { - arrayOf( - abUriParserLegacyFingerprint, - httpUriParserLegacyFingerprint, - ) - } - - fingerprints.forEach { - it.method.apply { - val insertIndex = findUriParseIndex() + arrayOf( + abUriParserFingerprint to 2, + httpUriParserFingerprint to 0 + ).forEach { (fingerprint, index) -> + fingerprint.method.apply { + val insertIndex = fingerprint.instructionMatches[index].index val uriStringRegister = getInstruction(insertIndex).registerC replaceInstruction( insertIndex, - "invoke-static {v$uriStringRegister}," + - "Lapp/revanced/extension/youtube/patches/BypassURLRedirectsPatch;" + - "->" + - "parseRedirectUri(Ljava/lang/String;)Landroid/net/Uri;", + "invoke-static { v$uriStringRegister }, $EXTENSION_CLASS_DESCRIPTOR->" + + "parseRedirectUri(Ljava/lang/String;)Landroid/net/Uri;", ) } } } } - -internal fun Method.findUriParseIndex() = indexOfFirstInstruction { - val reference = getReference() - reference?.returnType == "Landroid/net/Uri;" && reference.name == "parse" -} - -internal fun Method.findWebViewCheckCastIndex() = indexOfFirstInstruction { - val reference = getReference() - opcode == Opcode.CHECK_CAST && reference?.type?.endsWith("/WebviewEndpointOuterClass${'$'}WebviewEndpoint;") == true -} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/links/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/links/Fingerprints.kt index 6f231693b..cbd4a3c64 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/links/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/links/Fingerprints.kt @@ -1,68 +1,32 @@ package app.revanced.patches.youtube.misc.links +import app.revanced.patcher.checkCast +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint +import app.revanced.patcher.methodCall +import app.revanced.patcher.string import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode -/** - * Target 19.33+ - */ -internal val abUriParserFingerprint = fingerprint { +internal val abUriParserFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("Ljava/lang/Object") - parameters("Ljava/lang/Object") - custom { method, _ -> - method.findUriParseIndex() >= 0 && method.findWebViewCheckCastIndex() >= 0 - } -} - -/** - * Target 19.33+ - */ -internal val httpUriParserFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) - returns("Landroid/net/Uri") - parameters("Ljava/lang/String") - strings("https", "://", "https:") - custom { methodDef, _ -> - methodDef.findUriParseIndex() >= 0 - } -} - -internal val abUriParserLegacyFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("Ljava/lang/Object") - parameters("Ljava/lang/Object") - opcodes( - Opcode.RETURN_OBJECT, - Opcode.CHECK_CAST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.RETURN_OBJECT, - Opcode.CHECK_CAST, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.RETURN_OBJECT, - Opcode.CHECK_CAST, + returns("Ljava/lang/Object;") + parameters("Ljava/lang/Object;") + instructions( + string("Found entityKey=`"), + string("that does not contain a PlaylistVideoEntityId", partialMatch = true), + methodCall(smali = "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;") ) - custom { methodDef, classDef -> - // This method is always called "a" because this kind of class always has a single (non-synthetic) method. - - if (methodDef.name != "a") return@custom false - - val count = classDef.methods.count() - count == 2 || count == 3 - } } -internal val httpUriParserLegacyFingerprint = fingerprint { +internal val httpUriParserFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) - returns("Landroid/net/Uri") - parameters("Ljava/lang/String") - opcodes( - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, + returns("Landroid/net/Uri;") + parameters("Ljava/lang/String;") + instructions( + methodCall(smali = "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;"), + string("https"), + string("://"), + string("https:"), ) - strings("://") } + diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt index 497bd3c89..0740c3b69 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt @@ -1,30 +1,52 @@ package app.revanced.patches.youtube.misc.litho.filter +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint import app.revanced.util.containsLiteralInstruction -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.string import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val componentContextParserFingerprint = fingerprint { - strings("Number of bits must be positive") -} - -internal val componentCreateFingerprint = fingerprint { - strings( - "Element missing correct type extension", - "Element missing type" +internal val componentContextParserFingerprint by fingerprint { + instructions( + string("Number of bits must be positive") ) } -internal val lithoFilterFingerprint = fingerprint { +internal val componentCreateFingerprint by fingerprint { + instructions( + string("Element missing correct type extension"), + string("Element missing type") + ) +} + +internal val lithoFilterFingerprint by fingerprint { accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) custom { _, classDef -> classDef.endsWith("/LithoFilterPatch;") } } -internal val protobufBufferReferenceFingerprint = fingerprint { +internal val protobufBufferReferenceFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters("[B") + instructions( + fieldAccess( + opcode = Opcode.IGET_OBJECT, + definingClass = "this", + type = "Lcom/google/android/libraries/elements/adl/UpbMessage;" + ), + methodCall( + definingClass = "Lcom/google/android/libraries/elements/adl/UpbMessage;", + name = "jniDecode" + ) + ) +} + +internal val protobufBufferReferenceLegacyFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("I", "Ljava/nio/ByteBuffer;") @@ -36,34 +58,38 @@ internal val protobufBufferReferenceFingerprint = fingerprint { ) } -internal val emptyComponentFingerprint = fingerprint { +internal val emptyComponentFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.CONSTRUCTOR) parameters() - strings("EmptyComponent") + instructions( + string("EmptyComponent") + ) custom { _, classDef -> classDef.methods.filter { AccessFlags.STATIC.isSet(it.accessFlags) }.size == 1 } } -internal val lithoThreadExecutorFingerprint = fingerprint { +internal val lithoThreadExecutorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameters("I", "I", "I") custom { method, classDef -> classDef.superclass == "Ljava/util/concurrent/ThreadPoolExecutor;" && - method.containsLiteralInstruction(1L) // 1L = default thread timeout. + method.containsLiteralInstruction(1L) // 1L = default thread timeout. } } -internal val lithoComponentNameUpbFeatureFlagFingerprint = fingerprint { +internal val lithoComponentNameUpbFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() - literal { 45631264L } + instructions( + literal(45631264L) + ) } -internal val lithoConverterBufferUpbFeatureFlagFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) +internal val lithoConverterBufferUpbFeatureFlagFingerprint by fingerprint { returns("L") - parameters("L") - literal { 45419603L } + instructions( + literal(45419603L) + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt index 81ae57cbb..b03d8147d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt @@ -12,6 +12,7 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playservice.is_19_17_or_greater import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater import app.revanced.patches.youtube.misc.playservice.is_20_05_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_22_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.shared.conversionContextFingerprintToString import app.revanced.util.addInstructionsAtControlFlowLabel @@ -19,11 +20,13 @@ import app.revanced.util.findFreeRegister import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow +import app.revanced.util.insertLiteralOverride +import app.revanced.util.returnLate import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.reference.FieldReference +import java.util.logging.Logger lateinit var addLithoFilter: (String) -> Unit private set @@ -65,11 +68,11 @@ val lithoFilterPatch = bytecodePatch( * } * } * - * class CreateComponentClass { - * public Component createComponent() { + * class ComponentContextParser { + * public Component parseComponent() { * ... * - * if (extensionClass.shouldFilter(identifier, path)) { // Inserted by this patch. + * if (extensionClass.shouldFilter()) { // Inserted by this patch. * return emptyComponent; * } * return originalUnpatchedComponent; // Original code. @@ -90,32 +93,42 @@ val lithoFilterPatch = bytecodePatch( invoke-direct { v1 }, $classDescriptor->()V const/16 v2, ${filterCount++} aput-object v1, v0, v2 - """, + """ ) } } // region Pass the buffer into extension. - protobufBufferReferenceFingerprint.method.addInstruction( + if (is_20_22_or_greater) { + // Hook method that bridges between UPB buffer native code and FB Litho. + // Method is found in 19.25+, but is forcefully turned off for 20.21 and lower. + protobufBufferReferenceFingerprint.let { + // Hook the buffer after the call to jniDecode(). + it.method.addInstruction( + it.instructionMatches.last().index + 1, + "invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->setProtoBuffer([B)V", + ) + } + } + + // Legacy Non native buffer. + protobufBufferReferenceLegacyFingerprint.method.addInstruction( 0, "invoke-static { p2 }, $EXTENSION_CLASS_DESCRIPTOR->setProtoBuffer(Ljava/nio/ByteBuffer;)V", ) // endregion - // region Hook the method that parses bytes into a ComponentContext. - // Allow the method to run to completion, and override the - // return value with an empty component if it should be filtered. - // It is important to allow the original code to always run to completion, - // otherwise high memory usage and poor app performance can occur. + // region Modify the create component method and + // if the component is filtered then return an empty component. // Find the identifier/path fields of the conversion context. - val conversionContextIdentifierField = componentContextParserFingerprint.let { + val conversionContextIdentifierField = componentContextParserFingerprint.match().let { // Identifier field is loaded just before the string declaration. val index = it.method.indexOfFirstInstructionReversedOrThrow( - it.stringMatches!!.first().index + it.instructionMatches.first().index ) { val reference = getReference() reference?.definingClass == conversionContextFingerprintToString.originalClassDef.type @@ -136,7 +149,7 @@ val lithoFilterPatch = bytecodePatch( val emptyComponentField = classBy { // Only one field that matches. it.type == builderMethodDescriptor.returnType - }!!.immutableClass.fields.single() + }.fields.single() componentCreateFingerprint.method.apply { val insertIndex = if (is_19_17_or_greater) { @@ -199,23 +212,27 @@ val lithoFilterPatch = bytecodePatch( // Flag was removed in 20.05. It appears a new flag might be used instead (45660109L), // but if the flag is forced on then litho filtering still works correctly. if (is_19_25_or_greater && !is_20_05_or_greater) { - lithoComponentNameUpbFeatureFlagFingerprint.method.apply { - // Don't use return early, so the debug patch logs if this was originally on. - val insertIndex = indexOfFirstInstructionOrThrow(Opcode.RETURN) - val register = getInstruction(insertIndex).registerA - - addInstruction(insertIndex, "const/4 v$register, 0x0") - } + lithoComponentNameUpbFeatureFlagFingerprint.method.returnLate(false) } // Turn off a feature flag that enables native code of protobuf parsing (Upb protobuf). - // If this is enabled, then the litho protobuffer hook will always show an empty buffer - // since it's no longer handled by the hooked Java code. - lithoConverterBufferUpbFeatureFlagFingerprint.method.apply { - val index = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT) - val register = getInstruction(index).registerA + lithoConverterBufferUpbFeatureFlagFingerprint.let { + // Procool buffer has changed in 20.22, and UPB native code is now always enabled. + if (is_20_22_or_greater) { + Logger.getLogger(this::class.java.name).severe( + "\n!!!" + + "\n!!! Litho filtering is not yet fully supported when patching 20.22+" + + "\n!!! Action buttons, Shorts shelves, and possibly other components cannot be set hidden." + + "\n!!!" + ) + } - addInstruction(index + 1, "const/4 v$register, 0x0") + // 20.22 the flag is still enabled in one location, but what it does is not known. + // Disable it anyway. + it.method.insertLiteralOverride( + it.instructionMatches.first().index, + false + ) } // endregion @@ -224,4 +241,4 @@ val lithoFilterPatch = bytecodePatch( finalize { lithoFilterFingerprint.method.replaceInstruction(0, "const/16 v0, $filterCount") } -} +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt index a5fa0ed5e..5fbee6e27 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/Fingerprints.kt @@ -1,30 +1,37 @@ package app.revanced.patches.youtube.misc.navigation +import app.revanced.patcher.checkCast import app.revanced.patcher.fingerprint +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patcher.string +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import app.revanced.patches.youtube.layout.buttons.navigation.navigationButtonsPatch -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction -import app.revanced.util.literal 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 actionBarSearchResultsFingerprint = fingerprint { +internal val actionBarSearchResultsFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Landroid/view/View;") - literal { actionBarSearchResultsViewMicId } + instructions( + resourceLiteral(ResourceType.LAYOUT, "action_bar_search_results_view_mic"), + methodCall(name = "setLayoutDirection") + ) } -internal val toolbarLayoutFingerprint = fingerprint { +internal val toolbarLayoutFingerprint by fingerprint { accessFlags(AccessFlags.PROTECTED, AccessFlags.CONSTRUCTOR) - literal { toolbarContainerId } + instructions( + resourceLiteral(ResourceType.ID, "toolbar_container"), + checkCast("Lcom/google/android/apps/youtube/app/ui/actionbar/MainCollapsingToolbarLayout;") + ) } /** * Matches to https://android.googlesource.com/platform/frameworks/support/+/9eee6ba/v7/appcompat/src/android/support/v7/widget/Toolbar.java#963 */ -internal val appCompatToolbarBackButtonFingerprint = fingerprint { +internal val appCompatToolbarBackButtonFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Landroid/graphics/drawable/Drawable;") parameters() @@ -36,17 +43,19 @@ internal val appCompatToolbarBackButtonFingerprint = fingerprint { /** * Matches to the class found in [pivotBarConstructorFingerprint]. */ -internal val initializeButtonsFingerprint = fingerprint { +internal val initializeButtonsFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") - literal { imageOnlyTabResourceId } + instructions( + resourceLiteral(ResourceType.LAYOUT, "image_only_tab") + ) } /** * Extension method, used for callback into to other patches. * Specifically, [navigationButtonsPatch]. */ -internal val navigationBarHookCallbackFingerprint = fingerprint { +internal val navigationBarHookCallbackFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returns("V") parameters(EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR, "Landroid/view/View;") @@ -59,7 +68,7 @@ internal val navigationBarHookCallbackFingerprint = fingerprint { /** * Matches to the Enum class that looks up ordinal -> instance. */ -internal val navigationEnumFingerprint = fingerprint { +internal val navigationEnumFingerprint by fingerprint { accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) strings( "PIVOT_HOME", @@ -72,17 +81,17 @@ internal val navigationEnumFingerprint = fingerprint { ) } -internal val pivotBarButtonsCreateDrawableViewFingerprint = fingerprint { +internal val pivotBarButtonsCreateDrawableViewFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Landroid/view/View;") custom { method, _ -> method.definingClass == "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;" && - // Only one method has a Drawable parameter. + // Only one view creation method has a Drawable parameter. method.parameterTypes.firstOrNull() == "Landroid/graphics/drawable/Drawable;" } } -internal val pivotBarButtonsCreateResourceViewFingerprint = fingerprint { +internal val pivotBarButtonsCreateResourceStyledViewFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Landroid/view/View;") parameters("L", "Z", "I", "L") @@ -91,33 +100,50 @@ internal val pivotBarButtonsCreateResourceViewFingerprint = fingerprint { } } -internal fun indexOfSetViewSelectedInstruction(method: Method) = method.indexOfFirstInstruction { - opcode == Opcode.INVOKE_VIRTUAL && getReference()?.name == "setSelected" +/** + * 20.21+ + */ +internal val pivotBarButtonsCreateResourceIntViewFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("Landroid/view/View;") + custom { method, _ -> + method.definingClass == "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;" && + // Only one view creation method has an int first parameter. + method.parameterTypes.firstOrNull() == "I" + } } -internal val pivotBarButtonsViewSetSelectedFingerprint = fingerprint { +internal val pivotBarButtonsViewSetSelectedFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("I", "Z") + instructions( + methodCall(name = "setSelected") + ) custom { method, _ -> - indexOfSetViewSelectedInstruction(method) >= 0 && - method.definingClass == "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;" + method.definingClass == "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;" } } -internal val pivotBarConstructorFingerprint = fingerprint { +internal val pivotBarConstructorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - strings("com.google.android.apps.youtube.app.endpoint.flags") + instructions( + string("com.google.android.apps.youtube.app.endpoint.flags"), + ) } -internal val imageEnumConstructorFingerprint = fingerprint { +internal val imageEnumConstructorFingerprint by fingerprint { accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) - strings("TAB_ACTIVITY_CAIRO") + instructions( + string("TAB_ACTIVITY_CAIRO"), + opcode(Opcode.SPUT_OBJECT) + ) } -internal val setEnumMapFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - literal { - ytFillBellId - } +internal val setEnumMapFingerprint by fingerprint { + instructions( + resourceLiteral(ResourceType.DRAWABLE, "yt_fill_bell_black_24"), + methodCall(smali = "Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;", maxAfter = 10), + methodCall(smali = "Ljava/util/EnumMap;->put(Ljava/lang/Enum;Ljava/lang/Object;)Ljava/lang/Object;", maxAfter = 10) + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt index f1ea33327..c3e125dae 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch.kt @@ -6,20 +6,18 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable -import app.revanced.patches.shared.misc.mapping.get import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch import app.revanced.patches.youtube.misc.playservice.is_19_35_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_21_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_28_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.shared.mainActivityOnBackPressedFingerprint +import app.revanced.util.findFreeRegister import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.indexOfFirstInstructionReversedOrThrow -import app.revanced.util.indexOfFirstLiteralInstructionOrThrow import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation @@ -28,30 +26,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.Instruction 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.MethodReference -import com.android.tools.smali.dexlib2.iface.reference.TypeReference import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.util.MethodUtil -internal var imageOnlyTabResourceId = -1L - private set -internal var actionBarSearchResultsViewMicId = -1L - private set -internal var ytFillBellId = -1L - private set -internal var toolbarContainerId = -1L - private set - -private val navigationBarHookResourcePatch = resourcePatch { - dependsOn(resourceMappingPatch) - - execute { - imageOnlyTabResourceId = resourceMappings["layout", "image_only_tab"] - actionBarSearchResultsViewMicId = resourceMappings["layout", "action_bar_search_results_view_mic"] - ytFillBellId = resourceMappings["drawable", "yt_fill_bell_black_24"] - toolbarContainerId = resourceMappings["id", "toolbar_container"] - } -} - internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/shared/NavigationBar;" internal const val EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR = @@ -64,12 +41,13 @@ lateinit var hookNavigationButtonCreated: (String) -> Unit val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navigation or search bar.") { dependsOn( sharedExtensionPatch, - navigationBarHookResourcePatch, + versionCheckPatch, playerTypeHookPatch, // Required to detect the search bar in all situations. + resourceMappingPatch, // Used by fingerprints ) execute { - fun MutableMethod.addHook(hook: Hook, insertPredicate: Instruction.() -> Boolean) { + fun MutableMethod.addHook(hook: NavigationHook, insertPredicate: Instruction.() -> Boolean) { val filtered = instructions.filter(insertPredicate) if (filtered.isEmpty()) throw PatchException("Could not find insert indexes") filtered.forEach { @@ -87,22 +65,32 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig initializeButtonsFingerprint.match(pivotBarConstructorFingerprint.originalClassDef).method.apply { // Hook the current navigation bar enum value. Note, the 'You' tab does not have an enum value. val navigationEnumClassName = navigationEnumFingerprint.classDef.type - addHook(Hook.SET_LAST_APP_NAVIGATION_ENUM) { + addHook(NavigationHook.SET_LAST_APP_NAVIGATION_ENUM) { opcode == Opcode.INVOKE_STATIC && getReference()?.definingClass == navigationEnumClassName } // Hook the creation of navigation tab views. val drawableTabMethod = pivotBarButtonsCreateDrawableViewFingerprint.method - addHook(Hook.NAVIGATION_TAB_LOADED) predicate@{ + addHook(NavigationHook.NAVIGATION_TAB_LOADED) predicate@{ MethodUtil.methodSignaturesMatch( getReference() ?: return@predicate false, drawableTabMethod, ) } - val imageResourceTabMethod = pivotBarButtonsCreateResourceViewFingerprint.originalMethod - addHook(Hook.NAVIGATION_IMAGE_RESOURCE_TAB_LOADED) predicate@{ + if (is_20_21_or_greater && !is_20_28_or_greater) { + val imageResourceIntTabMethod = pivotBarButtonsCreateResourceIntViewFingerprint.originalMethod + addHook(NavigationHook.NAVIGATION_TAB_LOADED) predicate@{ + MethodUtil.methodSignaturesMatch( + getReference() ?: return@predicate false, + imageResourceIntTabMethod, + ) + } + } + + val imageResourceTabMethod = pivotBarButtonsCreateResourceStyledViewFingerprint.originalMethod + addHook(NavigationHook.NAVIGATION_IMAGE_RESOURCE_TAB_LOADED) predicate@{ MethodUtil.methodSignaturesMatch( getReference() ?: return@predicate false, imageResourceTabMethod, @@ -110,17 +98,19 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig } } - pivotBarButtonsViewSetSelectedFingerprint.method.apply { - val index = indexOfSetViewSelectedInstruction(this) - val instruction = getInstruction(index) - val viewRegister = instruction.registerC - val isSelectedRegister = instruction.registerD + pivotBarButtonsViewSetSelectedFingerprint.let { + it.method.apply { + val index = it.instructionMatches.first().index + val instruction = getInstruction(index) + val viewRegister = instruction.registerC + val isSelectedRegister = instruction.registerD - addInstruction( - index + 1, - "invoke-static { v$viewRegister, v$isSelectedRegister }, " + - "$EXTENSION_CLASS_DESCRIPTOR->navigationTabSelected(Landroid/view/View;Z)V", - ) + addInstruction( + index + 1, + "invoke-static { v$viewRegister, v$isSelectedRegister }, " + + "$EXTENSION_CLASS_DESCRIPTOR->navigationTabSelected(Landroid/view/View;Z)V", + ) + } } // Hook onto back button pressed. Needed to fix race problem with @@ -136,37 +126,31 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig // Two different layouts are used at the hooked code. // Insert before the first ViewGroup method call after inflating, // so this works regardless which layout is used. - actionBarSearchResultsFingerprint.method.apply { - val searchBarResourceId = indexOfFirstLiteralInstructionOrThrow( - actionBarSearchResultsViewMicId, - ) + actionBarSearchResultsFingerprint.let { + it.method.apply { + val instructionIndex = it.instructionMatches.last().index + val viewRegister = getInstruction(instructionIndex).registerC - val instructionIndex = indexOfFirstInstructionOrThrow(searchBarResourceId) { - opcode == Opcode.INVOKE_VIRTUAL && getReference()?.name == "setLayoutDirection" + addInstruction( + instructionIndex, + "invoke-static { v$viewRegister }, " + + "$EXTENSION_CLASS_DESCRIPTOR->searchBarResultsViewLoaded(Landroid/view/View;)V", + ) } - - val viewRegister = getInstruction(instructionIndex).registerC - - addInstruction( - instructionIndex, - "invoke-static { v$viewRegister }, " + - "$EXTENSION_CLASS_DESCRIPTOR->searchBarResultsViewLoaded(Landroid/view/View;)V", - ) } // Hook the back button visibility. - toolbarLayoutFingerprint.method.apply { - val index = indexOfFirstInstructionOrThrow { - opcode == Opcode.CHECK_CAST && getReference()?.type == - "Lcom/google/android/apps/youtube/app/ui/actionbar/MainCollapsingToolbarLayout;" - } - val register = getInstruction(index).registerA + toolbarLayoutFingerprint.let { + it.method.apply { + val index = it.instructionMatches.last().index + val register = getInstruction(index).registerA - addInstruction( - index + 1, - "invoke-static { v$register }, ${EXTENSION_CLASS_DESCRIPTOR}->setToolbar(Landroid/widget/FrameLayout;)V" - ) + addInstruction( + index + 1, + "invoke-static { v$register }, ${EXTENSION_CLASS_DESCRIPTOR}->setToolbar(Landroid/widget/FrameLayout;)V" + ) + } } // Add interface for extensions code to call obfuscated methods. @@ -212,37 +196,30 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig // Fix YT bug of notification tab missing the filled icon. if (is_19_35_or_greater) { - val cairoNotificationEnumReference = with(imageEnumConstructorFingerprint) { - val stringIndex = stringMatches!!.first().index - val cairoNotificationEnumIndex = method.indexOfFirstInstructionOrThrow(stringIndex) { - opcode == Opcode.SPUT_OBJECT - } - method.getInstruction(cairoNotificationEnumIndex).reference - } + val cairoNotificationEnumReference = imageEnumConstructorFingerprint + .instructionMatches.last().getInstruction().reference - setEnumMapFingerprint.method.apply { - val enumMapIndex = indexOfFirstInstructionReversedOrThrow { - val reference = getReference() - opcode == Opcode.INVOKE_VIRTUAL && - reference?.definingClass == "Ljava/util/EnumMap;" && - reference.name == "put" && - reference.parameterTypes.firstOrNull() == "Ljava/lang/Enum;" - } - val instruction = getInstruction(enumMapIndex) + setEnumMapFingerprint.let { + it.method.apply { + val setEnumIntegerIndex = it.instructionMatches.last().index + val enumMapRegister = getInstruction(setEnumIntegerIndex).registerC + val insertIndex = setEnumIntegerIndex + 1 + val freeRegister = findFreeRegister(insertIndex, enumMapRegister) - addInstructions( - enumMapIndex + 1, - """ - sget-object v${instruction.registerD}, $cairoNotificationEnumReference - invoke-static { v${instruction.registerC}, v${instruction.registerD} }, $EXTENSION_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V - """ - ) + addInstructions( + insertIndex, + """ + sget-object v$freeRegister, $cairoNotificationEnumReference + invoke-static { v$enumMapRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V + """ + ) + } } } } } -private enum class Hook(val methodName: String, val parameters: String) { +private enum class NavigationHook(val methodName: String, val parameters: String) { SET_LAST_APP_NAVIGATION_ENUM("setLastAppNavigationEnum", "Ljava/lang/Enum;"), NAVIGATION_TAB_LOADED("navigationTabLoaded", "Landroid/view/View;"), NAVIGATION_IMAGE_RESOURCE_TAB_LOADED("navigationImageResourceTabLoaded", "Landroid/view/View;"), diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt index da2137135..8d0a5a8e2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/Fingerprints.kt @@ -1,27 +1,16 @@ package app.revanced.patches.youtube.misc.playercontrols +import app.revanced.patcher.checkCast import app.revanced.patcher.fingerprint -import app.revanced.util.containsLiteralInstruction -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction -import app.revanced.util.indexOfFirstInstructionReversed -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral 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 fun indexOfFocusableInTouchModeInstruction(method: Method) = - method.indexOfFirstInstruction { - getReference()?.name == "setFocusableInTouchMode" - } - -internal fun indexOfTranslationInstruction(method: Method) = - method.indexOfFirstInstructionReversed { - getReference()?.name == "setTranslationY" - } - -internal val playerControlsVisibilityEntityModelFingerprint = fingerprint { +internal val playerControlsVisibilityEntityModelFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC) returns("L") parameters() @@ -34,34 +23,25 @@ internal val playerControlsVisibilityEntityModelFingerprint = fingerprint { } } -internal val youtubeControlsOverlayFingerprint = fingerprint { - accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) +internal val youtubeControlsOverlayFingerprint by fingerprint { returns("V") parameters() - custom { method, _ -> - indexOfFocusableInTouchModeInstruction(method) >= 0 && - method.containsLiteralInstruction(inset_overlay_view_layout_id) && - method.containsLiteralInstruction(scrim_overlay_id) - - } + instructions( + methodCall(name = "setFocusableInTouchMode"), + resourceLiteral(ResourceType.ID, "inset_overlay_view_layout"), + resourceLiteral(ResourceType.ID, "scrim_overlay"), + ) } -internal val motionEventFingerprint = fingerprint { +internal val motionEventFingerprint by fingerprint { returns("V") parameters("Landroid/view/MotionEvent;") - custom { method, _ -> - indexOfTranslationInstruction(method) >= 0 - } + instructions( + methodCall(name = "setTranslationY") + ) } -internal val playerTopControlsInflateFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("V") - parameters() - literal { controls_layout_stub_id } -} - -internal val playerControlsExtensionHookListenersExistFingerprint = fingerprint { +internal val playerControlsExtensionHookListenersExistFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returns("Z") parameters() @@ -71,7 +51,7 @@ internal val playerControlsExtensionHookListenersExistFingerprint = fingerprint } } -internal val playerControlsExtensionHookFingerprint = fingerprint { +internal val playerControlsExtensionHookFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC) returns("V") parameters("Z") @@ -81,42 +61,88 @@ internal val playerControlsExtensionHookFingerprint = fingerprint { } } -internal val playerBottomControlsInflateFingerprint = fingerprint { - returns("Ljava/lang/Object;") +internal val playerTopControlsInflateFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") parameters() - literal { bottom_ui_container_stub_id } + instructions( + resourceLiteral(ResourceType.ID, "controls_layout_stub"), + methodCall("Landroid/view/ViewStub;", "inflate"), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0) + ) } -internal val overlayViewInflateFingerprint = fingerprint { +internal val playerBottomControlsInflateFingerprint by fingerprint { + returns("Ljava/lang/Object;") + parameters() + instructions( + resourceLiteral(ResourceType.ID, "bottom_ui_container_stub"), + methodCall("Landroid/view/ViewStub;", "inflate"), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0) + ) +} + +internal val overlayViewInflateFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Landroid/view/View;") - custom { methodDef, _ -> - methodDef.containsLiteralInstruction(fullscreen_button_id) && - methodDef.containsLiteralInstruction(heatseeker_viewstub_id) - } + instructions( + resourceLiteral(ResourceType.ID, "heatseeker_viewstub"), + resourceLiteral(ResourceType.ID, "fullscreen_button"), + checkCast("Landroid/widget/ImageView;") + ) } /** * Resolves to the class found in [playerTopControlsInflateFingerprint]. */ -internal val controlsOverlayVisibilityFingerprint = fingerprint { +internal val controlsOverlayVisibilityFingerprint by fingerprint { accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) returns("V") parameters("Z", "Z") } -internal val playerBottomControlsExploderFeatureFlagFingerprint = fingerprint { +internal val playerBottomControlsExploderFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters() - literal { 45643739L } + instructions( + literal(45643739L) + ) } -internal val playerTopControlsExperimentalLayoutFeatureFlagFingerprint = fingerprint { +internal val playerTopControlsExperimentalLayoutFeatureFlagFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("I") parameters() - literal { 45629424L } + instructions( + literal(45629424L) + ) } +internal val playerControlsLargeOverlayButtonsFeatureFlagFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("Z") + parameters() + instructions( + literal(45709810L) + ) +} + +internal val playerControlsFullscreenLargeButtonsFeatureFlagFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("Z") + parameters() + instructions( + literal(45686474L) + ) +} + +internal val playerControlsButtonStrokeFeatureFlagFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("Z") + parameters() + instructions( + literal(45713296) + ) +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsOverlayVisibilityPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsOverlayVisibilityPatch.kt index e10725f76..ab0378e4a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsOverlayVisibilityPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsOverlayVisibilityPatch.kt @@ -12,13 +12,13 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction private const val EXTENSION_PLAYER_CONTROLS_VISIBILITY_HOOK_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/PlayerControlsVisibilityHookPatch;" -val PlayerControlsOverlayVisibilityPatch = bytecodePatch { +val playerControlsOverlayVisibilityPatch = bytecodePatch { dependsOn(sharedExtensionPatch) execute { playerControlsVisibilityEntityModelFingerprint.let { it.method.apply { - val startIndex = it.patternMatch!!.startIndex + val startIndex = it.instructionMatches.first().index val iGetReference = getInstruction(startIndex).reference val staticReference = getInstruction(startIndex + 1).reference diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsPatch.kt index e5949586d..00edcbe4f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/PlayerControlsPatch.kt @@ -7,17 +7,24 @@ import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.util.Document import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.misc.mapping.get import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater import app.revanced.patches.youtube.misc.playservice.is_19_35_or_greater -import app.revanced.util.* +import app.revanced.patches.youtube.misc.playservice.is_20_19_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_20_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_28_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_30_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch +import app.revanced.util.copyXmlNode +import app.revanced.util.findElementByAttributeValue +import app.revanced.util.findElementByAttributeValueOrThrow +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.inputStreamFromBundledResource +import app.revanced.util.returnEarly +import app.revanced.util.returnLate import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.reference.MethodReference -import com.android.tools.smali.dexlib2.iface.reference.TypeReference import org.w3c.dom.Node /** @@ -39,22 +46,7 @@ internal lateinit var addTopControl: (String) -> Unit lateinit var addBottomControl: (String) -> Unit private set -internal var bottom_ui_container_stub_id = -1L - private set -internal var controls_layout_stub_id = -1L - private set -internal var heatseeker_viewstub_id = -1L - private set -internal var fullscreen_button_id = -1L - private set -internal var inset_overlay_view_layout_id = -1L - private set -internal var scrim_overlay_id = -1L - private set - -val playerControlsResourcePatch = resourcePatch { - dependsOn(resourceMappingPatch) - +internal val playerControlsResourcePatch = resourcePatch { /** * The element to the left of the element being added. */ @@ -68,13 +60,6 @@ val playerControlsResourcePatch = resourcePatch { execute { val targetResourceName = "youtube_controls_bottom_ui_container.xml" - bottom_ui_container_stub_id = resourceMappings["id", "bottom_ui_container_stub"] - controls_layout_stub_id = resourceMappings["id", "controls_layout_stub"] - heatseeker_viewstub_id = resourceMappings["id", "heatseeker_viewstub"] - fullscreen_button_id = resourceMappings["id", "fullscreen_button"] - inset_overlay_view_layout_id = resourceMappings["id", "inset_overlay_view_layout"] - scrim_overlay_id = resourceMappings["id", "scrim_overlay"] - bottomTargetDocument = document("res/layout/$targetResourceName") val bottomTargetElement: Node = bottomTargetDocument.getElementsByTagName( @@ -189,16 +174,16 @@ fun initializeBottomControl(descriptor: String) { * @param descriptor The descriptor of the method which should be called. */ fun injectVisibilityCheckCall(descriptor: String) { - visibilityMethod.addInstruction( - visibilityInsertIndex++, - "invoke-static { p1 , p2 }, $descriptor->setVisibility(ZZ)V", - ) - if (!visibilityImmediateCallbacksExistModified) { visibilityImmediateCallbacksExistModified = true visibilityImmediateCallbacksExistMethod.returnEarly(true) } + visibilityMethod.addInstruction( + visibilityInsertIndex++, + "invoke-static { p1 , p2 }, $descriptor->setVisibility(ZZ)V", + ) + visibilityImmediateMethod.addInstruction( visibilityImmediateInsertIndex++, "invoke-static { p0 }, $descriptor->setVisibilityImmediate(Z)V", @@ -216,24 +201,24 @@ internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/PlayerControlsPatch;" private lateinit var inflateTopControlMethod: MutableMethod -private var inflateTopControlInsertIndex: Int = -1 -private var inflateTopControlRegister: Int = -1 +private var inflateTopControlInsertIndex = -1 +private var inflateTopControlRegister = -1 private lateinit var inflateBottomControlMethod: MutableMethod -private var inflateBottomControlInsertIndex: Int = -1 -private var inflateBottomControlRegister: Int = -1 +private var inflateBottomControlInsertIndex = -1 +private var inflateBottomControlRegister = -1 + +private lateinit var visibilityImmediateCallbacksExistMethod : MutableMethod +private var visibilityImmediateCallbacksExistModified = false private lateinit var visibilityMethod: MutableMethod -private var visibilityInsertIndex: Int = 0 - -private var visibilityImmediateCallbacksExistModified = false -private lateinit var visibilityImmediateCallbacksExistMethod : MutableMethod +private var visibilityInsertIndex = 0 private lateinit var visibilityImmediateMethod: MutableMethod -private var visibilityImmediateInsertIndex: Int = 0 +private var visibilityImmediateInsertIndex = 0 private lateinit var visibilityNegatedImmediateMethod: MutableMethod -private var visibilityNegatedImmediateInsertIndex: Int = 0 +private var visibilityNegatedImmediateInsertIndex = 0 val playerControlsPatch = bytecodePatch( description = "Manages the code for the player controls of the YouTube player.", @@ -241,30 +226,30 @@ val playerControlsPatch = bytecodePatch( dependsOn( playerControlsResourcePatch, sharedExtensionPatch, - PlayerControlsOverlayVisibilityPatch + resourceMappingPatch, // Used by fingerprints. + playerControlsOverlayVisibilityPatch, + versionCheckPatch ) execute { - fun MutableMethod.indexOfFirstViewInflateOrThrow() = indexOfFirstInstructionOrThrow { - val reference = getReference() - reference?.definingClass == "Landroid/view/ViewStub;" && - reference.name == "inflate" + playerBottomControlsInflateFingerprint.let { + it.method.apply { + inflateBottomControlMethod = this + + val inflateReturnObjectIndex = it.instructionMatches.last().index + inflateBottomControlRegister = getInstruction(inflateReturnObjectIndex).registerA + inflateBottomControlInsertIndex = inflateReturnObjectIndex + 1 + } } - playerBottomControlsInflateFingerprint.method.apply { - inflateBottomControlMethod = this + playerTopControlsInflateFingerprint.let { + it.method.apply { + inflateTopControlMethod = this - val inflateReturnObjectIndex = indexOfFirstViewInflateOrThrow() + 1 - inflateBottomControlRegister = getInstruction(inflateReturnObjectIndex).registerA - inflateBottomControlInsertIndex = inflateReturnObjectIndex + 1 - } - - playerTopControlsInflateFingerprint.method.apply { - inflateTopControlMethod = this - - val inflateReturnObjectIndex = indexOfFirstViewInflateOrThrow() + 1 - inflateTopControlRegister = getInstruction(inflateReturnObjectIndex).registerA - inflateTopControlInsertIndex = inflateReturnObjectIndex + 1 + val inflateReturnObjectIndex = it.instructionMatches.last().index + inflateTopControlRegister = getInstruction(inflateReturnObjectIndex).registerA + inflateTopControlInsertIndex = inflateReturnObjectIndex + 1 + } } visibilityMethod = controlsOverlayVisibilityFingerprint.match( @@ -273,29 +258,25 @@ val playerControlsPatch = bytecodePatch( // Hook the fullscreen close button. Used to fix visibility // when seeking and other situations. - overlayViewInflateFingerprint.method.apply { - val resourceIndex = indexOfFirstLiteralInstructionReversedOrThrow(fullscreen_button_id) + overlayViewInflateFingerprint.let { + it.method.apply { + val index = it.instructionMatches.last().index + val register = getInstruction(index).registerA - val index = indexOfFirstInstructionOrThrow(resourceIndex) { - opcode == Opcode.CHECK_CAST && - getReference()?.type == - "Landroid/widget/ImageView;" + addInstruction( + index + 1, + "invoke-static { v$register }, " + + "$EXTENSION_CLASS_DESCRIPTOR->setFullscreenCloseButton(Landroid/widget/ImageView;)V", + ) } - val register = getInstruction(index).registerA - - addInstruction( - index + 1, - "invoke-static { v$register }, " + - "$EXTENSION_CLASS_DESCRIPTOR->setFullscreenCloseButton(Landroid/widget/ImageView;)V", - ) } visibilityImmediateCallbacksExistMethod = playerControlsExtensionHookListenersExistFingerprint.method visibilityImmediateMethod = playerControlsExtensionHookFingerprint.method - motionEventFingerprint.match(youtubeControlsOverlayFingerprint.originalClassDef).method.apply { - visibilityNegatedImmediateMethod = this - visibilityNegatedImmediateInsertIndex = indexOfTranslationInstruction(this) + 1 + motionEventFingerprint.match(youtubeControlsOverlayFingerprint.originalClassDef).let { + visibilityNegatedImmediateMethod = it.method + visibilityNegatedImmediateInsertIndex = it.instructionMatches.first().index + 1 } // A/B test for a slightly different bottom overlay controls, @@ -306,24 +287,30 @@ val playerControlsPatch = bytecodePatch( playerBottomControlsExploderFeatureFlagFingerprint.method.returnLate(false) } - // A/B test of new top overlay controls. Two different layouts can be used: + // A/B test of different top overlay controls. Two different layouts can be used: // youtube_cf_navigation_improvement_controls_layout.xml // youtube_cf_minimal_impact_controls_layout.xml // - // Visually there is no noticeable difference between either of these compared to the default. - // There is additional logic that is active when youtube_cf_navigation_improvement_controls_layout - // is active, but what it does is not entirely clear. - // - // For now force this a/b feature off as it breaks the top player buttons. - if (is_19_25_or_greater) { + // Flag was removed in 20.19+ + if (is_19_25_or_greater && !is_20_19_or_greater) { playerTopControlsExperimentalLayoutFeatureFlagFingerprint.method.apply { val index = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_OBJECT) val register = getInstruction(index).registerA - addInstruction( - index + 1, - "const-string v$register, \"default\"" - ) + addInstruction(index + 1, "const-string v$register, \"default\"") + } + } + + // Turn off a/b tests of ugly player buttons that don't match the style of custom player buttons. + if (is_20_20_or_greater) { + playerControlsFullscreenLargeButtonsFeatureFlagFingerprint.method.returnLate(false) + + if (is_20_28_or_greater) { + playerControlsLargeOverlayButtonsFeatureFlagFingerprint.method.returnLate(false) + } + + if (is_20_30_or_greater) { + playerControlsButtonStrokeFeatureFlagFingerprint.method.returnLate(false) } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/Fingerprints.kt index 522d06b20..f3a4dba5b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/Fingerprints.kt @@ -1,35 +1,59 @@ package app.revanced.patches.youtube.misc.playertype import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.opcode +import app.revanced.patcher.string +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val playerTypeFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("V") - parameters("L") - opcodes( - Opcode.IF_NE, - Opcode.RETURN_VOID, +internal val playerTypeEnumFingerprint by fingerprint { + accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) + strings( + "NONE", + "HIDDEN", + "WATCH_WHILE_MINIMIZED", + "WATCH_WHILE_MAXIMIZED", + "WATCH_WHILE_FULLSCREEN", + "WATCH_WHILE_SLIDING_MAXIMIZED_FULLSCREEN", + "WATCH_WHILE_SLIDING_MINIMIZED_MAXIMIZED", + "WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED", + "INLINE_MINIMAL", + "VIRTUAL_REALITY_FULLSCREEN", + "WATCH_WHILE_PICTURE_IN_PICTURE", ) - custom { _, classDef -> classDef.endsWith("/YouTubePlayerOverlaysLayout;") } } -internal val reelWatchPagerFingerprint = fingerprint { +internal val reelWatchPagerFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Landroid/view/View;") - literal { reelWatchPlayerId } -} - -internal val videoStateFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("V") - parameters("Lcom/google/android/libraries/youtube/player/features/overlay/controls/ControlsState;") - opcodes( - Opcode.CONST_4, - Opcode.IF_EQZ, - Opcode.IF_EQZ, - Opcode.IGET_OBJECT, // obfuscated parameter field name + instructions( + resourceLiteral(ResourceType.ID, "reel_watch_player"), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 10) + ) +} + +internal val videoStateEnumFingerprint by fingerprint { + accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR) + parameters() + strings( + "NEW", + "PLAYING", + "PAUSED", + "RECOVERABLE_ERROR", + "UNRECOVERABLE_ERROR", + "ENDED" + ) +} + +// 20.33 and lower class name ControlsState. 20.34+ class name is obfuscated. +internal val controlsStateToStringFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + parameters() + returns("Ljava/lang/String;") + instructions( + string("videoState"), + string("isBuffering") ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/PlayerTypeHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/PlayerTypeHookPatch.kt index b14de0cbe..b2628cdcf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/PlayerTypeHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/PlayerTypeHookPatch.kt @@ -3,64 +3,82 @@ package app.revanced.patches.youtube.misc.playertype import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.fieldAccess +import app.revanced.patcher.fingerprint import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patcher.patch.resourcePatch -import app.revanced.patches.shared.misc.mapping.get +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch -import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.indexOfFirstLiteralInstructionOrThrow -import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/PlayerTypeHookPatch;" -internal var reelWatchPlayerId = -1L - private set - -private val playerTypeHookResourcePatch = resourcePatch { - dependsOn(resourceMappingPatch) - - execute { - reelWatchPlayerId = resourceMappings["id", "reel_watch_player"] - } -} - val playerTypeHookPatch = bytecodePatch( description = "Hook to get the current player type and video playback state.", ) { - dependsOn(sharedExtensionPatch, playerTypeHookResourcePatch) + dependsOn(sharedExtensionPatch, resourceMappingPatch) execute { - playerTypeFingerprint.method.addInstruction( + val playerOverlaysSetPlayerTypeFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters(playerTypeEnumFingerprint.originalClassDef.type) + custom { _, classDef -> + classDef.endsWith("/YouTubePlayerOverlaysLayout;") + } + } + + playerOverlaysSetPlayerTypeFingerprint.method.addInstruction( 0, - "invoke-static {p1}, $EXTENSION_CLASS_DESCRIPTOR->setPlayerType(Ljava/lang/Enum;)V", + "invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->setPlayerType(Ljava/lang/Enum;)V", ) - reelWatchPagerFingerprint.method.apply { - val literalIndex = indexOfFirstLiteralInstructionOrThrow(reelWatchPlayerId) - val registerIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT_OBJECT) - val viewRegister = getInstruction(registerIndex).registerA + reelWatchPagerFingerprint.let { + it.method.apply { + val index = it.instructionMatches.last().index + val register = getInstruction(index).registerA - addInstruction( - registerIndex + 1, - "invoke-static { v$viewRegister }, $EXTENSION_CLASS_DESCRIPTOR->onShortsCreate(Landroid/view/View;)V" + addInstruction( + index + 1, + "invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->onShortsCreate(Landroid/view/View;)V" + ) + } + } + + val controlStateType = controlsStateToStringFingerprint.originalClassDef.type + + val videoStateFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters(controlStateType) + instructions( + // Obfuscated parameter field name. + fieldAccess( + definingClass = controlStateType, + type = videoStateEnumFingerprint.originalClassDef.type + ), + resourceLiteral(ResourceType.STRING, "accessibility_play"), + resourceLiteral(ResourceType.STRING, "accessibility_pause") ) } - videoStateFingerprint.method.apply { - val endIndex = videoStateFingerprint.patternMatch!!.endIndex - val videoStateFieldName = getInstruction(endIndex).reference + videoStateFingerprint.let { + it.method.apply { + val videoStateFieldName = getInstruction( + it.instructionMatches.first().index + ).reference - addInstructions( - 0, - """ - iget-object v0, p1, $videoStateFieldName # copy VideoState parameter field - invoke-static {v0}, $EXTENSION_CLASS_DESCRIPTOR->setVideoState(Ljava/lang/Enum;)V - """ - ) + addInstructions( + 0, + """ + iget-object v0, p1, $videoStateFieldName # copy VideoState parameter field + invoke-static {v0}, $EXTENSION_CLASS_DESCRIPTOR->setVideoState(Ljava/lang/Enum;)V + """ + ) + } } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt index 4b29ca62c..62f8f560b 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/playservice/VersionCheckPatch.kt @@ -5,15 +5,6 @@ package app.revanced.patches.youtube.misc.playservice import app.revanced.patcher.patch.resourcePatch import app.revanced.util.findElementByAttributeValueOrThrow -@Deprecated("19.34.42 is the lowest supported version") -var is_19_03_or_greater = false - private set -@Deprecated("19.34.42 is the lowest supported version") -var is_19_04_or_greater = false - private set -@Deprecated("19.34.42 is the lowest supported version") -var is_19_16_or_greater = false - private set @Deprecated("19.34.42 is the lowest supported version") var is_19_17_or_greater = false private set @@ -70,6 +61,24 @@ var is_20_14_or_greater = false private set var is_20_15_or_greater = false private set +var is_20_19_or_greater = false + private set +var is_20_20_or_greater = false + private set +var is_20_21_or_greater = false + private set +var is_20_22_or_greater = false + private set +var is_20_26_or_greater = false + private set +var is_20_28_or_greater = false + private set +var is_20_30_or_greater = false + private set +var is_20_31_or_greater = false + private set +var is_20_34_or_greater = false + private set val versionCheckPatch = resourcePatch( description = "Uses the Play Store service version to find the major/minor version of the YouTube target app.", @@ -85,9 +94,6 @@ val versionCheckPatch = resourcePatch( } // All bug fix releases always seem to use the same play store version as the minor version. - is_19_03_or_greater = 240402000 <= playStoreServicesVersion - is_19_04_or_greater = 240502000 <= playStoreServicesVersion - is_19_16_or_greater = 241702000 <= playStoreServicesVersion is_19_17_or_greater = 241802000 <= playStoreServicesVersion is_19_18_or_greater = 241902000 <= playStoreServicesVersion is_19_23_or_greater = 242402000 <= playStoreServicesVersion @@ -112,5 +118,14 @@ val versionCheckPatch = resourcePatch( is_20_10_or_greater = 251105000 <= playStoreServicesVersion is_20_14_or_greater = 251505000 <= playStoreServicesVersion is_20_15_or_greater = 251605000 <= playStoreServicesVersion + is_20_19_or_greater = 252005000 <= playStoreServicesVersion + is_20_20_or_greater = 252105000 <= playStoreServicesVersion + is_20_21_or_greater = 252205000 <= playStoreServicesVersion + is_20_22_or_greater = 252305000 <= playStoreServicesVersion + is_20_26_or_greater = 252705000 <= playStoreServicesVersion + is_20_28_or_greater = 252905000 <= playStoreServicesVersion + is_20_30_or_greater = 253105000 <= playStoreServicesVersion + is_20_31_or_greater = 253205000 <= playStoreServicesVersion + is_20_34_or_greater = 253505000 <= playStoreServicesVersion } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/Fingerprints.kt index 72734bba7..f7d5fc0d4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/Fingerprints.kt @@ -1,44 +1,69 @@ package app.revanced.patches.youtube.misc.privacy -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.AccessFlags +import app.revanced.patcher.checkCast +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode +import app.revanced.patcher.string +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode -internal val copyTextFingerprint = fingerprint { +internal val copyTextFingerprint by fingerprint { returns("V") parameters("L", "Ljava/util/Map;") - opcodes( - Opcode.IGET_OBJECT, // Contains the text to copy to be sanitized. - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, // ClipData.newPlainText - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.RETURN_VOID, + instructions( + opcode(Opcode.IGET_OBJECT), + string("text/plain", maxAfter = 2), + methodCall( + smali = "Landroid/content/ClipData;->newPlainText(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Landroid/content/ClipData;", + maxAfter = 2 + ), + opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 2), + methodCall( + smali = "Landroid/content/ClipboardManager;->setPrimaryClip(Landroid/content/ClipData;)V", + maxAfter = 2 + ) ) - strings("text/plain") } -internal val systemShareSheetFingerprint = fingerprint { - returns("V") - parameters("L", "Ljava/util/Map;") - opcodes( - Opcode.CHECK_CAST, - Opcode.GOTO, - ) - strings("YTShare_Logging_Share_Intent_Endpoint_Byte_Array") -} - -internal val youtubeShareSheetFingerprint = fingerprint { +internal val youtubeShareSheetFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L", "Ljava/util/Map;") - opcodes( - Opcode.CHECK_CAST, - Opcode.GOTO, - Opcode.MOVE_OBJECT, - Opcode.INVOKE_VIRTUAL, + instructions( + methodCall( + smali = "Landroid/content/Intent;->setClassName(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;" + ), + + methodCall( + smali = "Ljava/util/List;->iterator()Ljava/util/Iterator;", + maxAfter = 4 + ), + + fieldAccess( + opcode = Opcode.IGET_OBJECT, + type = "Ljava/lang/String;", + maxAfter = 15 + ), + + methodCall( + smali = "Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;", + maxAfter = 15 + ) + ) +} + +internal val systemShareSheetFingerprint by fingerprint { + returns("V") + parameters("L", "Ljava/util/Map;") + instructions( + opcode(Opcode.IGET_OBJECT), + checkCast("Ljava/lang/String;", maxAfter = 0), + opcode(Opcode.GOTO, maxAfter = 0), + + methodCall(smali = "Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;"), + + string("YTShare_Logging_Share_Intent_Endpoint_Byte_Array") ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt index 235572eaa..bee7b2790 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt @@ -1,23 +1,23 @@ package app.revanced.patches.youtube.misc.privacy import app.revanced.patcher.Fingerprint -import app.revanced.patcher.Match import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.settingsPatch +import app.revanced.util.addInstructionsAtControlFlowLabel +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/RemoveTrackingQueryParameterPatch;" +// TODO: Rename this to "Sanitize sharing links" to be consistent with other apps. val removeTrackingQueryParameterPatch = bytecodePatch( name = "Remove tracking query parameter", description = "Adds an option to remove the tracking parameter from links you share.", @@ -46,34 +46,39 @@ val removeTrackingQueryParameterPatch = bytecodePatch( SwitchPreference("revanced_remove_tracking_query_parameter"), ) - fun Fingerprint.hook( - getInsertIndex: Match.PatternMatch.() -> Int, - getUrlRegister: MutableMethod.(insertIndex: Int) -> Int, - ) { - val insertIndex = patternMatch!!.getInsertIndex() - val urlRegister = method.getUrlRegister(insertIndex) + fun Fingerprint.hookUrlString(matchIndex: Int) { + val index = instructionMatches[matchIndex].index + val urlRegister = method.getInstruction(index).registerA method.addInstructions( - insertIndex, + index + 1, """ - invoke-static {v$urlRegister}, $EXTENSION_CLASS_DESCRIPTOR->sanitize(Ljava/lang/String;)Ljava/lang/String; + invoke-static { v$urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->sanitize(Ljava/lang/String;)Ljava/lang/String; move-result-object v$urlRegister - """, + """ ) } - // YouTube share sheet.\ - youtubeShareSheetFingerprint.hook(getInsertIndex = { startIndex + 1 }) { insertIndex -> - getInstruction(insertIndex - 1).registerA + fun Fingerprint.hookIntentPutExtra(matchIndex: Int) { + val index = instructionMatches[matchIndex].index + val urlRegister = method.getInstruction(index).registerE + + method.addInstructionsAtControlFlowLabel( + index, + """ + invoke-static { v$urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->sanitize(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$urlRegister + """ + ) } + // YouTube share sheet copy link. + copyTextFingerprint.hookUrlString(0) + + // YouTube share sheet other apps. + youtubeShareSheetFingerprint.hookIntentPutExtra(3) + // Native system share sheet. - systemShareSheetFingerprint.hook(getInsertIndex = { endIndex }) { insertIndex -> - getInstruction(insertIndex - 1).registerA - } - - copyTextFingerprint.hook(getInsertIndex = { startIndex + 2 }) { insertIndex -> - getInstruction(insertIndex - 2).registerA - } + systemShareSheetFingerprint.hookIntentPutExtra(3) } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/Fingerprints.kt index 09aa7bf4c..a2bf2ee30 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/Fingerprints.kt @@ -4,9 +4,8 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val recyclerViewTreeObserverFingerprint = fingerprint { +internal val recyclerViewTreeObserverFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") opcodes( Opcode.CHECK_CAST, Opcode.NEW_INSTANCE, diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt index 58033a223..10a4120d0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt @@ -12,7 +12,7 @@ val recyclerViewTreeHookPatch = bytecodePatch { execute { recyclerViewTreeObserverFingerprint.method.apply { - val insertIndex = recyclerViewTreeObserverFingerprint.patternMatch!!.startIndex + 1 + val insertIndex = recyclerViewTreeObserverFingerprint.instructionMatches.first().index + 1 val recyclerViewParameter = 2 addRecyclerViewTreeHook = { classDescriptor -> diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/Fingerprints.kt index 3dd3816b5..4c0554960 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/Fingerprints.kt @@ -1,29 +1,36 @@ package app.revanced.patches.youtube.misc.settings import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.opcode +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode -internal val licenseActivityOnCreateFingerprint = fingerprint { +internal val licenseActivityOnCreateFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") - parameters("L") + parameters("Landroid/os/Bundle;") custom { method, classDef -> - classDef.endsWith("LicenseActivity;") && method.name == "onCreate" + method.name == "onCreate" && classDef.endsWith("/LicenseActivity;") } } -internal val setThemeFingerprint = fingerprint { +internal val setThemeFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters() - literal { appearanceStringId } + instructions( + resourceLiteral(ResourceType.STRING, "app_theme_appearance_dark"), + ) } -internal const val CAIRO_CONFIG_LITERAL_VALUE = 45532100L - -internal val cairoFragmentConfigFingerprint = fingerprint { +internal val cairoFragmentConfigFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") - literal { CAIRO_CONFIG_LITERAL_VALUE } -} + instructions( + literal(45532100L), + opcode(Opcode.MOVE_RESULT, 10) + ) +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt index 672999b6a..4a83324e1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt @@ -8,9 +8,7 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMu import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName 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.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.overrideThemeColors import app.revanced.patches.shared.misc.settings.preference.* import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting @@ -32,9 +30,6 @@ import com.android.tools.smali.dexlib2.util.MethodUtil private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/settings/LicenseActivityHook;" -internal var appearanceStringId = -1L - private set - private val preferences = mutableSetOf() fun addSettingPreference(screen: BasePreference) { @@ -70,8 +65,6 @@ private val settingsResourcePatch = resourcePatch { ) execute { - appearanceStringId = resourceMappings["string", "app_theme_appearance_dark"] - // Use same colors as stock YouTube. overrideThemeColors("@color/yt_white1", "@color/yt_black3") @@ -221,14 +214,19 @@ val settingsPatch = bytecodePatch( // Modify the license activity and remove all existing layout code. // Must modify an existing activity and cannot add a new activity to the manifest, // as that fails for root installations. + licenseActivityOnCreateFingerprint.let { + val superClass = it.classDef.superclass - licenseActivityOnCreateFingerprint.method.addInstructions( - 1, - """ - invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->initialize(Landroid/app/Activity;)V - return-void - """ - ) + it.method.addInstructions( + 0, + """ + # Some targets have extra instructions before the call to super method. + invoke-super { p0, p1 }, $superClass->onCreate(Landroid/os/Bundle;)V + invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->initialize(Landroid/app/Activity;)V + return-void + """ + ) + } // Remove other methods as they will break as the onCreate method is modified above. licenseActivityOnCreateFingerprint.classDef.apply { @@ -315,11 +313,13 @@ val settingsPatch = bytecodePatch( } // Add setting to force cairo settings fragment on/off. - cairoFragmentConfigFingerprint.method.insertLiteralOverride( - CAIRO_CONFIG_LITERAL_VALUE, - "$EXTENSION_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z" - ) - } + cairoFragmentConfigFingerprint.let { + it.method.insertLiteralOverride( + it.instructionMatches.last().index, + "$EXTENSION_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z" + ) + } + } finalize { PreferenceScreen.close() diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/ZoomHapticsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/ZoomHapticsPatch.kt deleted file mode 100644 index 44cde6002..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/ZoomHapticsPatch.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.youtube.misc.zoomhaptics - -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.youtube.misc.hapticfeedback.disableHapticFeedbackPatch - -@Deprecated("Superseded by disableHapticFeedbackPatch", ReplaceWith("disableHapticFeedbackPatch")) -val zoomHapticsPatch = bytecodePatch( - description = "Adds an option to disable haptics when zooming.", -) { - dependsOn(disableHapticFeedbackPatch) -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt index 4a9f3a020..3272c913e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/shared/Fingerprints.kt @@ -1,10 +1,18 @@ package app.revanced.patches.youtube.shared +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.newInstance +import app.revanced.patcher.opcode +import app.revanced.patcher.string +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val conversionContextFingerprintToString = fingerprint { +internal val conversionContextFingerprintToString by fingerprint { parameters() strings( "ConversionContext{containerInternal=", @@ -19,7 +27,7 @@ internal val conversionContextFingerprintToString = fingerprint { } } -internal val autoRepeatFingerprint = fingerprint { +internal val autoRepeatFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters() @@ -28,23 +36,27 @@ internal val autoRepeatFingerprint = fingerprint { } } -internal val autoRepeatParentFingerprint = fingerprint { +internal val autoRepeatParentFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") - strings( - "play() called when the player wasn't loaded.", - "play() blocked because Background Playability failed", + instructions( + string("play() called when the player wasn't loaded."), + string("play() blocked because Background Playability failed") ) } -internal val layoutConstructorFingerprint = fingerprint { +internal val layoutConstructorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") - parameters() - strings("1.0x") + instructions( + literal(159962), + resourceLiteral(ResourceType.ID, "player_control_previous_button_touch_area"), + resourceLiteral(ResourceType.ID, "player_control_next_button_touch_area"), + methodCall(parameters = listOf("Landroid/view/View;", "I")) + ) } -internal val mainActivityConstructorFingerprint = fingerprint { +internal val mainActivityConstructorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameters() custom { _, classDef -> @@ -52,7 +64,7 @@ internal val mainActivityConstructorFingerprint = fingerprint { } } -internal val mainActivityOnBackPressedFingerprint = fingerprint { +internal val mainActivityOnBackPressedFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters() @@ -61,7 +73,7 @@ internal val mainActivityOnBackPressedFingerprint = fingerprint { } } -internal val mainActivityOnCreateFingerprint = fingerprint { +internal val mainActivityOnCreateFingerprint by fingerprint { returns("V") parameters("Landroid/os/Bundle;") custom { method, classDef -> @@ -69,7 +81,7 @@ internal val mainActivityOnCreateFingerprint = fingerprint { } } -internal val rollingNumberTextViewAnimationUpdateFingerprint = fingerprint { +internal val rollingNumberTextViewAnimationUpdateFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Landroid/graphics/Bitmap;") @@ -95,54 +107,42 @@ internal val rollingNumberTextViewAnimationUpdateFingerprint = fingerprint { } } -internal val seekbarFingerprint = fingerprint { +internal val seekbarFingerprint by fingerprint { returns("V") - strings("timed_markers_width") + instructions( + string("timed_markers_width"), + ) } -internal val seekbarOnDrawFingerprint = fingerprint { +/** + * Matches to _mutable_ class found in [seekbarFingerprint]. + */ +internal val seekbarOnDrawFingerprint by fingerprint { + instructions( + methodCall(smali = "Ljava/lang/Math;->round(F)I"), + opcode(Opcode.MOVE_RESULT, maxAfter = 0) + ) custom { method, _ -> method.name == "onDraw" } } -internal val subtitleButtonControllerFingerprint = fingerprint { +internal val subtitleButtonControllerFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("Lcom/google/android/libraries/youtube/player/subtitles/model/SubtitleTrack;") - opcodes( - Opcode.IGET_OBJECT, - Opcode.IF_NEZ, - Opcode.RETURN_VOID, - Opcode.IGET_BOOLEAN, - Opcode.CONST_4, - Opcode.IF_NEZ, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.IGET_OBJECT, + instructions( + resourceLiteral(ResourceType.STRING, "accessibility_captions_unavailable"), + resourceLiteral(ResourceType.STRING, "accessibility_captions_button_name"), ) } -internal val videoQualityChangedFingerprint = fingerprint { +internal val videoQualityChangedFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters("L") - opcodes( - Opcode.IGET, // Video resolution (human readable). - Opcode.IGET_OBJECT, - Opcode.IGET_BOOLEAN, - Opcode.IGET_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_DIRECT, - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.GOTO, - Opcode.CONST_4, - Opcode.IF_NE, - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IGET, + instructions( + newInstance("Lcom/google/android/libraries/youtube/innertube/model/media/VideoQuality;"), + opcode(Opcode.IGET_OBJECT), + opcode(Opcode.CHECK_CAST), + fieldAccess(type = "I", opcode = Opcode.IGET, maxAfter = 0), // Video resolution (human readable). ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/Fingerprints.kt index 8e3755bc8..a9cdc2ecf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/audio/Fingerprints.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint import app.revanced.util.containsLiteralInstruction import com.android.tools.smali.dexlib2.AccessFlags -internal val formatStreamModelToStringFingerprint = fingerprint { +internal val formatStreamModelToStringFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Ljava/lang/String;") custom { method, classDef -> @@ -15,7 +15,7 @@ internal val formatStreamModelToStringFingerprint = fingerprint { internal const val AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG = 45666189L -internal val selectAudioStreamFingerprint = fingerprint { +internal val selectAudioStreamFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("L") custom { method, _ -> diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/information/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/information/Fingerprints.kt index 74b0e0864..5327e6244 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/information/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/information/Fingerprints.kt @@ -1,18 +1,22 @@ package app.revanced.patches.youtube.video.information +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint +import app.revanced.patcher.string import app.revanced.patches.youtube.shared.videoQualityChangedFingerprint import app.revanced.util.getReference import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.reference.FieldReference -internal val createVideoPlayerSeekbarFingerprint = fingerprint { +internal val createVideoPlayerSeekbarFingerprint by fingerprint { returns("V") - strings("timed_markers_width") + instructions( + string("timed_markers_width"), + ) } -internal val onPlaybackSpeedItemClickFingerprint = fingerprint { +internal val onPlaybackSpeedItemClickFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L", "L", "I", "J") @@ -25,23 +29,27 @@ internal val onPlaybackSpeedItemClickFingerprint = fingerprint { } } -internal val playerControllerSetTimeReferenceFingerprint = fingerprint { +internal val playerControllerSetTimeReferenceFingerprint by fingerprint { opcodes(Opcode.INVOKE_DIRECT_RANGE, Opcode.IGET_OBJECT) strings("Media progress reported outside media playback: ") } -internal val playerInitFingerprint = fingerprint { - strings("playVideo called on player response with no videoStreamingData.") +internal val playerInitFingerprint by fingerprint { + instructions( + string("playVideo called on player response with no videoStreamingData."), + ) } /** * Matched using class found in [playerInitFingerprint]. */ -internal val seekFingerprint = fingerprint { - strings("Attempting to seek during an ad") +internal val seekFingerprint by fingerprint { + instructions( + string("Attempting to seek during an ad"), + ) } -internal val videoLengthFingerprint = fingerprint { +internal val videoLengthFingerprint by fingerprint { opcodes( Opcode.MOVE_RESULT_WIDE, Opcode.CMP_LONG, @@ -61,7 +69,7 @@ internal val videoLengthFingerprint = fingerprint { /** * Matches using class found in [mdxPlayerDirectorSetVideoStageFingerprint]. */ -internal val mdxSeekFingerprint = fingerprint { +internal val mdxSeekFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") parameters("J", "L") @@ -78,19 +86,20 @@ internal val mdxSeekFingerprint = fingerprint { } } -internal val mdxPlayerDirectorSetVideoStageFingerprint = fingerprint { - strings("MdxDirector setVideoStage ad should be null when videoStage is not an Ad state ") +internal val mdxPlayerDirectorSetVideoStageFingerprint by fingerprint { + instructions( + string("MdxDirector setVideoStage ad should be null when videoStage is not an Ad state "), + ) } /** * Matches using class found in [mdxPlayerDirectorSetVideoStageFingerprint]. */ -internal val mdxSeekRelativeFingerprint = fingerprint { +internal val mdxSeekRelativeFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) // Return type is boolean up to 19.39, and void with 19.39+. parameters("J", "L") opcodes( - Opcode.IGET_OBJECT, Opcode.INVOKE_INTERFACE, ) @@ -99,7 +108,7 @@ internal val mdxSeekRelativeFingerprint = fingerprint { /** * Matches using class found in [playerInitFingerprint]. */ -internal val seekRelativeFingerprint = fingerprint { +internal val seekRelativeFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) // Return type is boolean up to 19.39, and void with 19.39+. parameters("J", "L") @@ -112,19 +121,16 @@ internal val seekRelativeFingerprint = fingerprint { /** * Resolves with the class found in [videoQualityChangedFingerprint]. */ -internal val playbackSpeedMenuSpeedChangedFingerprint = fingerprint { +internal val playbackSpeedMenuSpeedChangedFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters("L") - opcodes( - Opcode.IGET, - Opcode.INVOKE_VIRTUAL, - Opcode.SGET_OBJECT, - Opcode.RETURN_OBJECT, + instructions( + fieldAccess(opcode = Opcode.IGET, type = "F") ) } -internal val playbackSpeedClassFingerprint = fingerprint { +internal val playbackSpeedClassFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("L") parameters("L") @@ -137,7 +143,10 @@ internal val playbackSpeedClassFingerprint = fingerprint { internal const val YOUTUBE_VIDEO_QUALITY_CLASS_TYPE = "Lcom/google/android/libraries/youtube/innertube/model/media/VideoQuality;" -internal val videoQualityFingerprint = fingerprint { +/** + * YouTube 20.19 and lower. + */ +internal val videoQualityLegacyFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) parameters( "I", // Resolution. @@ -150,7 +159,21 @@ internal val videoQualityFingerprint = fingerprint { } } -internal val videoQualitySetterFingerprint = fingerprint { +internal val videoQualityFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) + parameters( + "I", // Resolution. + "L", + "Ljava/lang/String;", // Human readable resolution: "480p", "1080p Premium", etc + "Z", + "L" + ) + custom { _, classDef -> + classDef.type == YOUTUBE_VIDEO_QUALITY_CLASS_TYPE + } +} + +internal val videoQualitySetterFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("[L", "I", "Z") @@ -167,7 +190,7 @@ internal val videoQualitySetterFingerprint = fingerprint { /** * Matches with the class found in [videoQualitySetterFingerprint]. */ -internal val setVideoQualityFingerprint = fingerprint { +internal val setVideoQualityFingerprint by fingerprint { returns("V") parameters("L") opcodes( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt index 368aff634..05738010c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt @@ -9,6 +9,9 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.smali.toInstructions import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch +import app.revanced.patches.youtube.misc.playservice.is_20_19_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_20_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.shared.videoQualityChangedFingerprint import app.revanced.patches.youtube.video.playerresponse.Hook import app.revanced.patches.youtube.video.playerresponse.addPlayerResponseMethodHook @@ -82,6 +85,7 @@ val videoInformationPatch = bytecodePatch( sharedExtensionPatch, videoIdPatch, playerResponseMethodHookPatch, + versionCheckPatch, ) execute { @@ -127,12 +131,12 @@ val videoInformationPatch = bytecodePatch( val videoLengthMethodMatch = videoLengthFingerprint.match(originalClassDef) videoLengthMethodMatch.method.apply { - val videoLengthRegisterIndex = videoLengthMethodMatch.patternMatch!!.endIndex - 2 + val videoLengthRegisterIndex = videoLengthMethodMatch.instructionMatches.last().index - 2 val videoLengthRegister = getInstruction(videoLengthRegisterIndex).registerA val dummyRegisterForLong = videoLengthRegister + 1 // required for long values since they are wide addInstruction( - videoLengthMethodMatch.patternMatch!!.endIndex, + videoLengthMethodMatch.instructionMatches.last().index, "invoke-static {v$videoLengthRegister, v$dummyRegisterForLong}, " + "$EXTENSION_CLASS_DESCRIPTOR->setVideoLength(J)V", ) @@ -161,7 +165,7 @@ val videoInformationPatch = bytecodePatch( * Set the video time method */ timeMethod = navigate(playerControllerSetTimeReferenceFingerprint.originalMethod) - .to(playerControllerSetTimeReferenceFingerprint.patternMatch!!.startIndex) + .to(playerControllerSetTimeReferenceFingerprint.instructionMatches.first().index) .stop() /* @@ -188,8 +192,8 @@ val videoInformationPatch = bytecodePatch( getInstruction(indexOfFirstInstructionOrThrow(Opcode.IF_EQZ) - 1).reference as FieldReference setPlaybackSpeedMethod = - proxy(classes.first { it.type == setPlaybackSpeedMethodReference.definingClass }) - .mutableClass.methods.first { it.name == setPlaybackSpeedMethodReference.name } + mutableClassBy(setPlaybackSpeedMethodReference.definingClass) + .methods.first { it.name == setPlaybackSpeedMethodReference.name } setPlaybackSpeedMethodIndex = 0 // Add override playback speed method. @@ -262,20 +266,23 @@ val videoInformationPatch = bytecodePatch( // Handle new playback speed menu. playbackSpeedMenuSpeedChangedFingerprint.match( videoQualityChangedFingerprint.originalClassDef, - ).method.apply { - val index = indexOfFirstInstructionOrThrow(Opcode.IGET) + ).let { + it.method.apply { + val index = it.instructionMatches.first().index - speedSelectionInsertMethod = this - speedSelectionInsertIndex = index + 1 - speedSelectionValueRegister = getInstruction(index).registerA + speedSelectionInsertMethod = this + speedSelectionInsertIndex = index + 1 + speedSelectionValueRegister = getInstruction(index).registerA + } } - videoQualityFingerprint.let { + (if (is_20_19_or_greater) videoQualityFingerprint else videoQualityLegacyFingerprint).let { // Fix bad data used by YouTube. + val nameRegister = if (is_20_20_or_greater) "p3" else "p2" it.method.addInstructions( 0, """ - invoke-static { p2, p1 }, $EXTENSION_CLASS_DESCRIPTOR->fixVideoQualityResolution(Ljava/lang/String;I)I + invoke-static { $nameRegister, p1 }, $EXTENSION_CLASS_DESCRIPTOR->fixVideoQualityResolution(Ljava/lang/String;I)I move-result p1 """ ) @@ -345,11 +352,7 @@ val videoInformationPatch = bytecodePatch( val setQualityFieldReference = match.method .getInstruction(1).reference as FieldReference - proxy( - classes.find { classDef -> - classDef.type == setQualityFieldReference.type - }!! - ).mutableClass.apply { + mutableClassBy(setQualityFieldReference.type).apply { // Add interface and helper methods to allow extension code to call obfuscated methods. interfaces.add(EXTENSION_VIDEO_QUALITY_MENU_INTERFACE) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/Fingerprints.kt index d958285b4..7d0d3b109 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/Fingerprints.kt @@ -1,13 +1,13 @@ package app.revanced.patches.youtube.video.playerresponse import app.revanced.patcher.fingerprint +import app.revanced.patcher.string import com.android.tools.smali.dexlib2.AccessFlags -import org.stringtemplate.v4.compiler.Bytecode.instructions /** - * For targets 20.15 and later. + * For targets 20.26 and later. */ -internal val playerParameterBuilderFingerprint = fingerprint { +internal val playerParameterBuilderFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters( @@ -25,15 +25,46 @@ internal val playerParameterBuilderFingerprint = fingerprint { "L", "Z", // Appears to indicate if the video id is being opened or is currently playing. "Z", - "Z" + "Z", + "Lj\$/time/Duration;" + ) + instructions( + string("psps") + ) +} + +/** + * For targets 20.15 to 20.25 + */ +internal val playerParameterBuilder2015Fingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("L") + parameters( + "Ljava/lang/String;", // VideoId. + "[B", + "Ljava/lang/String;", // Player parameters proto buffer. + "Ljava/lang/String;", + "I", + "Z", + "I", + "L", + "Ljava/util/Set;", + "Ljava/lang/String;", + "Ljava/lang/String;", + "L", + "Z", // Appears to indicate if the video id is being opened or is currently playing. + "Z", + "Z", + ) + instructions( + string("psps") ) - strings("psps") } /** * For targets 20.10 to 20.14. */ -internal val playerParameterBuilder2010Fingerprint = fingerprint { +internal val playerParameterBuilder2010Fingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters( @@ -54,13 +85,15 @@ internal val playerParameterBuilder2010Fingerprint = fingerprint { "Z", "Z" ) - strings("psps") + instructions( + string("psps") + ) } /** * For targets 20.02 to 20.09. */ -internal val playerParameterBuilder2002Fingerprint = fingerprint { +internal val playerParameterBuilder2002Fingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters( @@ -80,13 +113,15 @@ internal val playerParameterBuilder2002Fingerprint = fingerprint { "Z", "Z", ) - strings("psps") + instructions( + string("psps"), + ) } /** * For targets 19.25 to 19.50. */ -internal val playerParameterBuilder1925Fingerprint = fingerprint { +internal val playerParameterBuilder1925Fingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters( @@ -105,13 +140,15 @@ internal val playerParameterBuilder1925Fingerprint = fingerprint { "Z", "Z", ) - strings("psps") + instructions( + string("psps") + ) } /** - * For targets 19.24 and earlier. + * For targets 19.01 to 19.24. */ -internal val playerParameterBuilderLegacyFingerprint = fingerprint { +internal val playerParameterBuilderLegacyFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt index 898f40096..34013b407 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt @@ -10,6 +10,7 @@ import app.revanced.patches.youtube.misc.playservice.is_19_23_or_greater import app.revanced.patches.youtube.misc.playservice.is_20_02_or_greater import app.revanced.patches.youtube.misc.playservice.is_20_10_or_greater import app.revanced.patches.youtube.misc.playservice.is_20_15_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_26_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch private val hooks = mutableSetOf() @@ -40,9 +41,12 @@ val playerResponseMethodHookPatch = bytecodePatch { execute { val fingerprint : Fingerprint - if (is_20_15_or_greater) { + if (is_20_26_or_greater) { parameterIsShortAndOpeningOrPlaying = 13 fingerprint = playerParameterBuilderFingerprint + } else if (is_20_15_or_greater) { + parameterIsShortAndOpeningOrPlaying = 13 + fingerprint = playerParameterBuilder2015Fingerprint } else if (is_20_10_or_greater) { parameterIsShortAndOpeningOrPlaying = 13 fingerprint = playerParameterBuilder2010Fingerprint diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/AdvancedVideoQualityMenuPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/AdvancedVideoQualityMenuPatch.kt index 3e8aa23a1..ef7ad9022 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/AdvancedVideoQualityMenuPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/AdvancedVideoQualityMenuPatch.kt @@ -5,12 +5,11 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.PatchException 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.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter @@ -25,23 +24,6 @@ internal var videoQualityBottomSheetListFragmentTitle = -1L internal var videoQualityQuickMenuAdvancedMenuDescription = -1L private set -private val advancedVideoQualityMenuResourcePatch = resourcePatch { - dependsOn(resourceMappingPatch) - - execute { - // Used for the old type of the video quality menu. - videoQualityBottomSheetListFragmentTitle = resourceMappings[ - "layout", - "video_quality_bottom_sheet_list_fragment_title", - ] - - videoQualityQuickMenuAdvancedMenuDescription = resourceMappings[ - "string", - "video_quality_quick_menu_advanced_menu_description", - ] - } -} - private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/playback/quality/AdvancedVideoQualityMenuPatch;" @@ -50,12 +32,12 @@ private const val FILTER_CLASS_DESCRIPTOR = internal val advancedVideoQualityMenuPatch = bytecodePatch { dependsOn( - advancedVideoQualityMenuResourcePatch, sharedExtensionPatch, settingsPatch, addResourcesPatch, lithoFilterPatch, recyclerViewTreeHookPatch, + resourceMappingPatch ) execute { @@ -65,12 +47,23 @@ internal val advancedVideoQualityMenuPatch = bytecodePatch { SwitchPreference("revanced_advanced_video_quality_menu") ) + // Used for the old type of the video quality menu. + videoQualityBottomSheetListFragmentTitle = getResourceId( + ResourceType.LAYOUT, + "video_quality_bottom_sheet_list_fragment_title", + ) + + videoQualityQuickMenuAdvancedMenuDescription = getResourceId( + ResourceType.STRING, + "video_quality_quick_menu_advanced_menu_description", + ) + // region Patch for the old type of the video quality menu. // Used for regular videos when spoofing to old app version, // and for the Shorts quality flyout on newer app versions. videoQualityMenuViewInflateFingerprint.let { it.method.apply { - val checkCastIndex = it.patternMatch!!.endIndex + val checkCastIndex = it.instructionMatches.last().index val listViewRegister = getInstruction(checkCastIndex).registerA addInstruction( @@ -83,9 +76,9 @@ internal val advancedVideoQualityMenuPatch = bytecodePatch { // Force YT to add the 'advanced' quality menu for Shorts. videoQualityMenuOptionsFingerprint.let { - val patternMatch = it.patternMatch!! - val startIndex = patternMatch.startIndex - val insertIndex = patternMatch.endIndex + val patternMatch = it.instructionMatches + val startIndex = patternMatch.first().index + val insertIndex = patternMatch.last().index if (startIndex != 0) throw PatchException("Unexpected opcode start index: $startIndex") it.method.apply { diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt index 09ec88f9c..44b54b647 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/Fingerprints.kt @@ -1,19 +1,22 @@ package app.revanced.patches.youtube.video.quality import app.revanced.patcher.fingerprint +import app.revanced.patcher.string import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val videoQualityItemOnClickParentFingerprint = fingerprint { +internal val videoQualityItemOnClickParentFingerprint by fingerprint { returns("V") - strings("VIDEO_QUALITIES_MENU_BOTTOM_SHEET_FRAGMENT") + instructions( + string("VIDEO_QUALITIES_MENU_BOTTOM_SHEET_FRAGMENT"), + ) } /** * Resolves to class found in [videoQualityItemOnClickFingerprint]. */ -internal val videoQualityItemOnClickFingerprint = fingerprint { +internal val videoQualityItemOnClickFingerprint by fingerprint { returns("V") parameters( "Landroid/widget/AdapterView;", @@ -27,7 +30,7 @@ internal val videoQualityItemOnClickFingerprint = fingerprint { } -internal val videoQualityMenuOptionsFingerprint = fingerprint { +internal val videoQualityMenuOptionsFingerprint by fingerprint { accessFlags(AccessFlags.STATIC) returns("[L") parameters("Landroid/content/Context", "L", "L") @@ -41,7 +44,7 @@ internal val videoQualityMenuOptionsFingerprint = fingerprint { literal { videoQualityQuickMenuAdvancedMenuDescription } } -internal val videoQualityMenuViewInflateFingerprint = fingerprint { +internal val videoQualityMenuViewInflateFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("L") parameters("L", "L", "L") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt index 2f67487c8..45034652f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt @@ -9,6 +9,8 @@ import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch +import app.revanced.patches.youtube.misc.playservice.is_20_20_or_greater +import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.shared.videoQualityChangedFingerprint import app.revanced.patches.youtube.video.information.onCreateHook @@ -25,6 +27,7 @@ val rememberVideoQualityPatch = bytecodePatch { playerTypeHookPatch, settingsPatch, addResourcesPatch, + versionCheckPatch, ) execute { @@ -68,16 +71,15 @@ val rememberVideoQualityPatch = bytecodePatch { ) // Inject a call to remember the user selected quality for regular videos. - videoQualityChangedFingerprint.let { - it.method.apply { - val index = it.patternMatch!!.startIndex - val register = getInstruction(index).registerA + videoQualityChangedFingerprint.method.apply { + val index = videoQualityChangedFingerprint.instructionMatches[3].index + val register = getInstruction(index).registerA - addInstruction( - index + 1, - "invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->userChangedQuality(I)V", - ) - } + addInstruction( + index + 1, + "invoke-static { v$register }, " + + "$EXTENSION_CLASS_DESCRIPTOR->userChangedQuality(I)V", + ) } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityDialogButtonPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityDialogButtonPatch.kt index d2618bb63..0473f29db 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityDialogButtonPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityDialogButtonPatch.kt @@ -13,7 +13,7 @@ import app.revanced.util.ResourceGroup import app.revanced.util.copyResources private val videoQualityButtonResourcePatch = resourcePatch { - dependsOn(playerControlsResourcePatch) + dependsOn(playerControlsPatch) execute { copyResources( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/button/PlaybackSpeedButtonPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/button/PlaybackSpeedButtonPatch.kt index 4885aa0fe..2d752eb6d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/button/PlaybackSpeedButtonPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/button/PlaybackSpeedButtonPatch.kt @@ -17,7 +17,7 @@ import app.revanced.util.ResourceGroup import app.revanced.util.copyResources private val playbackSpeedButtonResourcePatch = resourcePatch { - dependsOn(playerControlsResourcePatch) + dependsOn(playerControlsPatch) execute { copyResources( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt index b46375571..f981e31e0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt @@ -7,34 +7,27 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable 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.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.settings.preference.InputType import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.TextPreference +import app.revanced.patches.youtube.interaction.seekbar.customTapAndHoldFingerprint import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch -import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater +import app.revanced.patches.youtube.misc.playservice.is_19_47_or_greater +import app.revanced.patches.youtube.misc.playservice.is_20_34_or_greater import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.recyclerviewtree.hook.addRecyclerViewTreeHook import app.revanced.patches.youtube.misc.recyclerviewtree.hook.recyclerViewTreeHookPatch import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.video.speed.settingsMenuVideoSpeedGroup -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.indexOfFirstLiteralInstruction import app.revanced.util.indexOfFirstLiteralInstructionOrThrow import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.reference.FieldReference -import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.immutable.ImmutableField private const val FILTER_CLASS_DESCRIPTOR = @@ -43,17 +36,6 @@ private const val FILTER_CLASS_DESCRIPTOR = internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/playback/speed/CustomPlaybackSpeedPatch;" -internal var speedUnavailableId = -1L - private set - -private val customPlaybackSpeedResourcePatch = resourcePatch { - dependsOn(resourceMappingPatch) - - execute { - speedUnavailableId = resourceMappings["string", "varispeed_unavailable_message"] - } -} - internal val customPlaybackSpeedPatch = bytecodePatch( description = "Adds custom playback speed options.", ) { @@ -64,7 +46,7 @@ internal val customPlaybackSpeedPatch = bytecodePatch( lithoFilterPatch, versionCheckPatch, recyclerViewTreeHookPatch, - customPlaybackSpeedResourcePatch + resourceMappingPatch ) execute { @@ -81,20 +63,17 @@ internal val customPlaybackSpeedPatch = bytecodePatch( ) ) - if (is_19_25_or_greater) { + if (is_19_47_or_greater) { settingsMenuVideoSpeedGroup.add( TextPreference("revanced_speed_tap_and_hold", inputType = InputType.NUMBER_DECIMAL), ) } // Override the min/max speeds that can be used. - speedLimiterFingerprint.method.apply { + (if (is_20_34_or_greater) speedLimiterFingerprint else speedLimiterLegacyFingerprint).method.apply { val limitMinIndex = indexOfFirstLiteralInstructionOrThrow(0.25f) - var limitMaxIndex = indexOfFirstLiteralInstruction(2.0f) - // Newer targets have 4x max speed. - if (limitMaxIndex < 0) { - limitMaxIndex = indexOfFirstLiteralInstructionOrThrow(4.0f) - } + // Older unsupported targets use 2.0f and not 4.0f + val limitMaxIndex = indexOfFirstLiteralInstructionOrThrow(4.0f) val limitMinRegister = getInstruction(limitMinIndex).registerA val limitMaxRegister = getInstruction(limitMaxIndex).registerA @@ -103,42 +82,38 @@ internal val customPlaybackSpeedPatch = bytecodePatch( replaceInstruction(limitMaxIndex, "const/high16 v$limitMaxRegister, 8.0f") } + // region Force old video quality menu. // Replace the speeds float array with custom speeds. - // These speeds are used if the speed menu is immediately opened after a video is opened. - speedArrayGeneratorFingerprint.method.apply { - val sizeCallIndex = indexOfFirstInstructionOrThrow { getReference()?.name == "size" } - val sizeCallResultRegister = getInstruction(sizeCallIndex + 1).registerA + speedArrayGeneratorFingerprint.let { + val matches = it.instructionMatches + it.method.apply { + val playbackSpeedsArrayType = "$EXTENSION_CLASS_DESCRIPTOR->customPlaybackSpeeds:[F" + // Apply changes from last index to first to preserve indexes. - replaceInstruction(sizeCallIndex + 1, "const/4 v$sizeCallResultRegister, 0x0") + val originalArrayFetchIndex = matches[5].index + val originalArrayFetchDestination = matches[5].getInstruction().registerA + replaceInstruction( + originalArrayFetchIndex, + "sget-object v$originalArrayFetchDestination, $playbackSpeedsArrayType" + ) - val arrayLengthConstIndex = indexOfFirstLiteralInstructionOrThrow(7) - val arrayLengthConstDestination = getInstruction(arrayLengthConstIndex).registerA - val playbackSpeedsArrayType = "$EXTENSION_CLASS_DESCRIPTOR->customPlaybackSpeeds:[F" + val arrayLengthConstDestination = matches[3].getInstruction().registerA + val newArrayIndex = matches[4].index + addInstructions( + newArrayIndex, + """ + sget-object v$arrayLengthConstDestination, $playbackSpeedsArrayType + array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination + """ + ) - addInstructions( - arrayLengthConstIndex + 1, - """ - sget-object v$arrayLengthConstDestination, $playbackSpeedsArrayType - array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination - """, - ) - - val originalArrayFetchIndex = indexOfFirstInstructionOrThrow { - val reference = getReference() - reference?.type == "[F" && reference.definingClass.endsWith("/PlayerConfigModel;") + val sizeCallIndex = matches[0].index + 1 + val sizeCallResultRegister = getInstruction(sizeCallIndex).registerA + replaceInstruction(sizeCallIndex, "const/4 v$sizeCallResultRegister, 0x0") } - val originalArrayFetchDestination = - getInstruction(originalArrayFetchIndex).registerA - - replaceInstruction( - originalArrayFetchIndex, - "sget-object v$originalArrayFetchDestination, $playbackSpeedsArrayType", - ) } - // region Force old video quality menu. - // Add a static INSTANCE field to the class. // This is later used to call "showOldPlaybackSpeedMenu" on the instance. @@ -179,28 +154,30 @@ internal val customPlaybackSpeedPatch = bytecodePatch( // endregion - // Close the unpatched playback dialog and show the modern custom dialog. + // Close the unpatched playback dialog and show the custom speeds. addRecyclerViewTreeHook(EXTENSION_CLASS_DESCRIPTOR) // Required to check if the playback speed menu is currently shown. addLithoFilter(FILTER_CLASS_DESCRIPTOR) + // endregion + // region Custom tap and hold 2x speed. - if (is_19_25_or_greater) { - disableFastForwardNoticeFingerprint.method.apply { - val index = indexOfFirstInstructionOrThrow { - (this as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() - } - val register = getInstruction(index).registerA + if (is_19_47_or_greater) { + customTapAndHoldFingerprint.let { + it.method.apply { + val index = it.instructionMatches.first().index + val register = getInstruction(index).registerA - addInstructions( - index + 1, - """ + addInstructions( + index + 1, + """ invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->tapAndHoldSpeed()F move-result v$register """ - ) + ) + } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/Fingerprints.kt index f39a4136f..d738870cf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/Fingerprints.kt @@ -1,36 +1,64 @@ package app.revanced.patches.youtube.video.speed.custom +import app.revanced.patcher.fieldAccess import app.revanced.patcher.fingerprint -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.newInstance +import app.revanced.patcher.opcode +import app.revanced.patcher.string +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.resourceLiteral import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.reference.StringReference -internal val getOldPlaybackSpeedsFingerprint = fingerprint { + +internal val getOldPlaybackSpeedsFingerprint by fingerprint { parameters("[L", "I") strings("menu_item_playback_speed") } -internal val showOldPlaybackSpeedMenuFingerprint = fingerprint { - literal { speedUnavailableId } +internal val showOldPlaybackSpeedMenuFingerprint by fingerprint { + instructions( + resourceLiteral(ResourceType.STRING, "varispeed_unavailable_message") + ) } -internal val showOldPlaybackSpeedMenuExtensionFingerprint = fingerprint { - custom { method, classDef -> - method.name == "showOldPlaybackSpeedMenu" && classDef.type == EXTENSION_CLASS_DESCRIPTOR - } +internal val showOldPlaybackSpeedMenuExtensionFingerprint by fingerprint { + custom { method, _ -> method.name == "showOldPlaybackSpeedMenu" } } -internal val speedArrayGeneratorFingerprint = fingerprint { +internal val speedArrayGeneratorFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("[L") parameters("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;") - strings("0.0#") + instructions( + methodCall(name = "size", returnType = "I"), + newInstance("Ljava/text/DecimalFormat;"), + string("0.0#"), + literal(7), + opcode(Opcode.NEW_ARRAY), + fieldAccess(definingClass = "/PlayerConfigModel;", type = "[F") + ) } -internal val speedLimiterFingerprint = fingerprint { +/** + * 20.34+ + */ +internal val speedLimiterFingerprint by fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters("F", "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;") + instructions( + literal(0.25f), + literal(4.0f) + ) +} + +/** + * 20.33 and lower. + */ +internal val speedLimiterLegacyFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("F") @@ -45,16 +73,3 @@ internal val speedLimiterFingerprint = fingerprint { Opcode.INVOKE_STATIC, ) } - -internal val disableFastForwardNoticeFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("V") - parameters() - custom { method, _ -> - method.name == "run" && method.indexOfFirstInstruction { - // In later targets the code is found in different methods with different strings. - val string = getReference()?.string - string == "Failed to easy seek haptics vibrate." || string == "search_landing_cache_key" - } >= 0 - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/Fingerprints.kt index 3924588b4..5c73615f7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/Fingerprints.kt @@ -1,8 +1,11 @@ package app.revanced.patches.youtube.video.speed.remember import app.revanced.patcher.fingerprint +import app.revanced.patcher.string -internal val initializePlaybackSpeedValuesFingerprint = fingerprint { +internal val initializePlaybackSpeedValuesFingerprint by fingerprint { parameters("[L", "I") - strings("menu_item_playback_speed") + instructions( + string("menu_item_playback_speed"), + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/Fingerprints.kt index 6d4a3c6cb..9c8fbbc23 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/Fingerprints.kt @@ -1,55 +1,54 @@ package app.revanced.patches.youtube.video.videoid import app.revanced.patcher.fingerprint -import app.revanced.util.literal +import app.revanced.patcher.literal +import app.revanced.patcher.methodCall +import app.revanced.patcher.opcode import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal val videoIdFingerprint = fingerprint { +internal val videoIdFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("V") parameters("L") - opcodes( - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, + instructions( + methodCall( + definingClass = "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;", + returnType = "Ljava/lang/String;" + ), + opcode(Opcode.MOVE_RESULT_OBJECT), ) - custom { method, _ -> - method.indexOfPlayerResponseModelString() >= 0 - } } -internal val videoIdBackgroundPlayFingerprint = fingerprint { +internal val videoIdBackgroundPlayFingerprint by fingerprint { accessFlags(AccessFlags.DECLARED_SYNCHRONIZED, AccessFlags.FINAL, AccessFlags.PUBLIC) returns("V") parameters("L") - opcodes( - Opcode.IF_EQZ, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.MONITOR_EXIT, - Opcode.RETURN_VOID, - Opcode.MONITOR_EXIT, - Opcode.RETURN_VOID + instructions( + methodCall( + definingClass = "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;", + returnType = "Ljava/lang/String;" + ), + opcode(Opcode.MOVE_RESULT_OBJECT), + opcode(Opcode.IPUT_OBJECT), + opcode(Opcode.MONITOR_EXIT), + opcode(Opcode.RETURN_VOID), + opcode(Opcode.MONITOR_EXIT), + opcode(Opcode.RETURN_VOID) ) // The target snippet of code is buried in a huge switch block and the target method // has been changed many times by YT which makes identifying it more difficult than usual. custom { method, classDef -> - // Access flags changed in 19.36 - AccessFlags.FINAL.isSet(method.accessFlags) && - AccessFlags.DECLARED_SYNCHRONIZED.isSet(method.accessFlags) && - classDef.methods.count() == 17 && - method.implementation != null && - method.indexOfPlayerResponseModelString() >= 0 + classDef.methods.count() == 17 && + method.implementation != null } - } -internal val videoIdParentFingerprint = fingerprint { +internal val videoIdParentFingerprint by fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("[L") parameters("L") - literal { 524288L } + instructions( + literal(524288L) + ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt index 6d69381cd..7ffdb3b2e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt @@ -9,11 +9,7 @@ import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch import app.revanced.patches.youtube.video.playerresponse.Hook import app.revanced.patches.youtube.video.playerresponse.addPlayerResponseMethodHook import app.revanced.patches.youtube.video.playerresponse.playerResponseMethodHookPatch -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction -import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.reference.MethodReference /** * Hooks the new video id when the video changes. @@ -96,24 +92,22 @@ val videoIdPatch = bytecodePatch( ) execute { - videoIdFingerprint.match(videoIdParentFingerprint.originalClassDef).method.apply { - videoIdMethod = this - val index = indexOfPlayerResponseModelString() - videoIdRegister = getInstruction(index + 1).registerA - videoIdInsertIndex = index + 2 + videoIdFingerprint.match(videoIdParentFingerprint.originalClassDef).let { + it.method.apply { + videoIdMethod = this + val index = it.instructionMatches.first().index + videoIdRegister = getInstruction(index + 1).registerA + videoIdInsertIndex = index + 2 + } } - videoIdBackgroundPlayFingerprint.method.apply { - backgroundPlaybackMethod = this - val index = indexOfPlayerResponseModelString() - backgroundPlaybackVideoIdRegister = getInstruction(index + 1).registerA - backgroundPlaybackInsertIndex = index + 2 + videoIdBackgroundPlayFingerprint.let { + it.method.apply { + backgroundPlaybackMethod = this + val index = it.instructionMatches.first().index + backgroundPlaybackVideoIdRegister = getInstruction(index + 1).registerA + backgroundPlaybackInsertIndex = index + 2 + } } } -} - -internal fun Method.indexOfPlayerResponseModelString() = indexOfFirstInstruction { - val reference = getReference() - reference?.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;" && - reference.returnType == "Ljava/lang/String;" -} +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt deleted file mode 100644 index 537a2b68c..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.youtube.video.videoqualitymenu - -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.youtube.video.quality.videoQualityPatch - -@Suppress("unused") -@Deprecated("Use 'Video Quality' instead.") -val restoreOldVideoQualityMenuPatch = bytecodePatch { - dependsOn(videoQualityPatch) -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/Fingerprints.kt deleted file mode 100644 index af38f28f4..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/Fingerprints.kt +++ /dev/null @@ -1,20 +0,0 @@ -package app.revanced.patches.yuka.misc.unlockpremium - -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.AccessFlags -import app.revanced.patcher.fingerprint - -internal val isPremiumFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("Z") - opcodes( - Opcode.IGET_BOOLEAN, - Opcode.RETURN, - ) -} - -internal val yukaUserConstructorFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") - strings("premiumProvider") -} diff --git a/patches/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/UnlockPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/UnlockPremiumPatch.kt deleted file mode 100644 index c4cedd092..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/UnlockPremiumPatch.kt +++ /dev/null @@ -1,23 +0,0 @@ -package app.revanced.patches.yuka.misc.unlockpremium - -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.patch.bytecodePatch - -@Deprecated("This patch no longer works and will be removed in the future.") -@Suppress("unused") -val unlockPremiumPatch = bytecodePatch { - - compatibleWith("io.yuka.android"("4.29")) - - execute { - isPremiumFingerprint.match( - yukaUserConstructorFingerprint.originalClassDef, - ).method.addInstructions( - 0, - """ - const/4 v0, 0x1 - return v0 - """, - ) - } -} diff --git a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index 993fa820b..73b96693d 100644 --- a/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -14,9 +14,9 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableField import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.misc.mapping.get +import app.revanced.patches.shared.misc.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId import app.revanced.patches.shared.misc.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.util.InstructionUtils.Companion.branchOpcodes import app.revanced.util.InstructionUtils.Companion.returnOpcodes import app.revanced.util.InstructionUtils.Companion.writeOpcodes @@ -97,7 +97,8 @@ fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): In return bestFreeRegisterFound } // This method is simple and does not follow branching. - throw IllegalArgumentException("Encountered a branch statement before a free register could be found") + throw IllegalArgumentException("Encountered a branch statement before " + + "a free register could be found from startIndex: $startIndex") } if (instruction.isReturnInstruction) { @@ -359,8 +360,7 @@ fun MutableMethod.addInstructionsAtControlFlowLabel( * @see [indexOfFirstResourceIdOrThrow], [indexOfFirstLiteralInstructionReversed] */ fun Method.indexOfFirstResourceId(resourceName: String): Int { - val resourceId = resourceMappings["id", resourceName] - return indexOfFirstLiteralInstruction(resourceId) + return indexOfFirstLiteralInstruction(getResourceId(ResourceType.ID, resourceName)) } /** @@ -544,7 +544,7 @@ fun BytecodePatchContext.traverseClassHierarchy(targetClass: MutableClass, callb targetClass.superclass ?: return - classBy { targetClass.superclass == it.type }?.mutableClass?.let { + mutableClassByOrNull(targetClass.superclass!!)?.let { traverseClassHierarchy(it, callback) } } @@ -756,8 +756,12 @@ fun Method.findInstructionIndicesReversedOrThrow(opcode: Opcode): List { * Suitable for calls to extension code to override boolean and integer values. */ internal fun MutableMethod.insertLiteralOverride(literal: Long, extensionMethodDescriptor: String) { - // TODO: make this work with objects and wide values. val literalIndex = indexOfFirstLiteralInstructionOrThrow(literal) + insertLiteralOverride(literalIndex, extensionMethodDescriptor) +} + +internal fun MutableMethod.insertLiteralOverride(literalIndex: Int, extensionMethodDescriptor: String) { + // TODO: make this work with objects and wide primitive values. val index = indexOfFirstInstructionOrThrow(literalIndex, MOVE_RESULT) val register = getInstruction(index).registerA @@ -781,6 +785,13 @@ internal fun MutableMethod.insertLiteralOverride(literal: Long, extensionMethodD */ internal fun MutableMethod.insertLiteralOverride(literal: Long, override: Boolean) { val literalIndex = indexOfFirstLiteralInstructionOrThrow(literal) + return insertLiteralOverride(literalIndex, override) +} + +/** + * Constant value override of the first MOVE_RESULT after the index parameter. + */ +internal fun MutableMethod.insertLiteralOverride(literalIndex: Int, override: Boolean) { val index = indexOfFirstInstructionOrThrow(literalIndex, MOVE_RESULT) val register = getInstruction(index).registerA val overrideValue = if (override) "0x1" else "0x0" @@ -813,21 +824,7 @@ fun BytecodePatchContext.forEachLiteralValueInstruction( } if (matchingIndexes.isNotEmpty()) { - val mutableMethod = proxy(classDef).mutableClass.findMutableMethodOf(method) - - // FIXME: Until patcher V22 is merged, this workaround is needed - // because if multiple patches modify the same class - // then after modifying the method indexes of immutable classes - // are no longer correct. - matchingIndexes.clear() - mutableMethod.instructions.forEachIndexed { index, instruction -> - if ((instruction as? WideLiteralInstruction)?.wideLiteral == literal) { - matchingIndexes.add(index) - } - } - if (matchingIndexes.isEmpty()) return@forEach - // FIXME Remove code above after V22 merge. - + val mutableMethod = mutableClassBy(classDef).findMutableMethodOf(method) matchingIndexes.asReversed().forEach { index -> block.invoke(mutableMethod, index) } @@ -841,17 +838,29 @@ fun BytecodePatchContext.forEachLiteralValueInstruction( private const val RETURN_TYPE_MISMATCH = "Mismatch between override type and Method return type" /** - * Overrides the first instruction of a method with a constant `Boolean` return value. + * Overrides the first instruction of a method with a return-void instruction. * None of the method code will ever execute. * + * @see returnLate + */ +fun MutableMethod.returnEarly() { + check(returnType.first() == 'V') { + RETURN_TYPE_MISMATCH + } + overrideReturnValue(false.toHexString(), false) +} + +/** + * Overrides the first instruction of a method with a constant `Boolean` return value. + * None of the original method code will execute. + * * For methods that return an object or any array type, calling this method with `false` * will force the method to return a `null` value. * * @see returnLate */ -fun MutableMethod.returnEarly(value: Boolean = false) { - val returnType = returnType.first() - check(returnType == 'Z' || (!value && (returnType == 'V' || returnType == 'L' || returnType != '['))) { +fun MutableMethod.returnEarly(value: Boolean) { + check(returnType.first() == 'Z') { RETURN_TYPE_MISMATCH } overrideReturnValue(value.toHexString(), false) @@ -859,7 +868,7 @@ fun MutableMethod.returnEarly(value: Boolean = false) { /** * Overrides the first instruction of a method with a constant `Byte` return value. - * None of the method code will ever execute. + * None of the original method code will execute. * * @see returnLate */ @@ -870,7 +879,7 @@ fun MutableMethod.returnEarly(value: Byte) { /** * Overrides the first instruction of a method with a constant `Short` return value. - * None of the method code will ever execute. + * None of the original method code will execute. * * @see returnLate */ @@ -881,7 +890,7 @@ fun MutableMethod.returnEarly(value: Short) { /** * Overrides the first instruction of a method with a constant `Char` return value. - * None of the method code will ever execute. + * None of the original method code will execute. * * @see returnLate */ @@ -892,7 +901,7 @@ fun MutableMethod.returnEarly(value: Char) { /** * Overrides the first instruction of a method with a constant `Int` return value. - * None of the method code will ever execute. + * None of the original method code will execute. * * @see returnLate */ @@ -903,7 +912,7 @@ fun MutableMethod.returnEarly(value: Int) { /** * Overrides the first instruction of a method with a constant `Long` return value. - * None of the method code will ever execute. + * None of the original method code will execute. * * @see returnLate */ @@ -914,7 +923,7 @@ fun MutableMethod.returnEarly(value: Long) { /** * Overrides the first instruction of a method with a constant `Float` return value. - * None of the method code will ever execute. + * None of the original method code will execute. * * @see returnLate */ @@ -925,7 +934,7 @@ fun MutableMethod.returnEarly(value: Float) { /** * Overrides the first instruction of a method with a constant `Double` return value. - * None of the method code will ever execute. + * None of the original method code will execute. * * @see returnLate */ @@ -936,7 +945,7 @@ fun MutableMethod.returnEarly(value: Double) { /** * Overrides the first instruction of a method with a constant String return value. - * None of the method code will ever execute. + * None of the original method code will execute. * * Target method must have return type * Ljava/lang/String; or Ljava/lang/CharSequence; @@ -950,6 +959,21 @@ fun MutableMethod.returnEarly(value: String) { overrideReturnValue(value, false) } +/** + * Overrides the first instruction of a method with a constant `NULL` return value. + * None of the original method code will execute. + * + * @param value Value must be `Null`. + * @see returnLate + */ +fun MutableMethod.returnEarly(value: Void?) { + val returnType = returnType.first() + check(returnType == 'L' || returnType != '[') { + RETURN_TYPE_MISMATCH + } + overrideReturnValue(false.toHexString(), false) +} + /** * Overrides all return statements with a constant `Boolean` value. * All method code is executed the same as unpatched. @@ -960,11 +984,7 @@ fun MutableMethod.returnEarly(value: String) { * @see returnEarly */ fun MutableMethod.returnLate(value: Boolean) { - val returnType = returnType.first() - if (returnType == 'V') { - error("Cannot return late for Method of void type") - } - check(returnType == 'Z' || (!value && (returnType == 'L' || returnType == '['))) { + check(this.returnType.first() == 'Z') { RETURN_TYPE_MISMATCH } @@ -1064,6 +1084,22 @@ fun MutableMethod.returnLate(value: String) { overrideReturnValue(value, true) } +/** + * Overrides all return statements with a constant `Null` value. + * All method code is executed the same as unpatched. + * + * @param value Value must be `Null`. + * @see returnEarly + */ +fun MutableMethod.returnLate(value: Void?) { + val returnType = returnType.first() + check(returnType == 'L' || returnType == '[') { + RETURN_TYPE_MISMATCH + } + + overrideReturnValue(false.toHexString(), true) +} + private fun MutableMethod.overrideReturnValue(value: String, returnLate: Boolean) { val instructions = if (returnType == "Ljava/lang/String;" || returnType == "Ljava/lang/CharSequence;" ) { """ @@ -1140,10 +1176,7 @@ internal fun BytecodePatchContext.addStaticFieldToExtension( objectClass: String, smaliInstructions: String ) { - val classDef = classes.find { classDef -> classDef.type == className } - ?: throw PatchException("No matching methods found in: $className") - val mutableClass = proxy(classDef).mutableClass - + val mutableClass = mutableClassBy(className) val objectCall = "$mutableClass->$fieldName:$objectClass" mutableClass.apply { @@ -1175,7 +1208,7 @@ internal fun BytecodePatchContext.addStaticFieldToExtension( * * @param literalSupplier The supplier for the literal value to check for. */ -// TODO: add a way for subclasses to also use their own custom fingerprint. +@Deprecated("Instead use instruction filters and `literal()`") fun FingerprintBuilder.literal(literalSupplier: () -> Long) { custom { method, _ -> method.containsLiteralInstruction(literalSupplier()) diff --git a/patches/src/main/resources/addresources/values/arrays.xml b/patches/src/main/resources/addresources/values/arrays.xml index 454ed0c1e..9a9a29dd9 100644 --- a/patches/src/main/resources/addresources/values/arrays.xml +++ b/patches/src/main/resources/addresources/values/arrays.xml @@ -384,14 +384,6 @@ - - @string/revanced_shorts_player_type_shorts - @string/revanced_shorts_player_type_regular_player - - - SHORTS_PLAYER - REGULAR_PLAYER - @string/revanced_shorts_player_type_shorts @string/revanced_shorts_player_type_regular_player diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index e1df14c83..eead7f1bc 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -704,6 +704,9 @@ If changing this setting does not take effect, try switching to Incognito mode." Hide navigation button labels Labels are hidden Labels are shown + Enable navigation bar animations + Navigation transitions are animated + Navigation transitions are not animated Disable translucent status bar Status bar is opaque Status bar is opaque or translucent @@ -823,6 +826,9 @@ To show the Audio track menu, change \'Spoof video streams\' to iOS TV" Hide video thumbnails seekbar Video thumbnails seekbar is hidden Video thumbnails seekbar is shown + Enable fullscreen large seekbar + Fullscreen seekbar is large size + Fullscreen seekbar is normal size Shorts player