feat(Spotify): Add Hide Create button
patch (#5062)
This commit is contained in:
@ -10,7 +10,7 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
package app.revanced.extension.spotify.layout.hide.createbutton;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import app.revanced.extension.shared.Utils;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class HideCreateButtonPatch {
|
||||
|
||||
/**
|
||||
* A list of ids of resources which contain the Create button title.
|
||||
*/
|
||||
private static final List<String> CREATE_BUTTON_TITLE_RES_ID_LIST = List.of(
|
||||
Integer.toString(Utils.getResourceIdentifier("navigationbar_musicappitems_create_title", "string"))
|
||||
);
|
||||
|
||||
/**
|
||||
* The old id of the resource which contained the Create button title. Used in older versions of the app.
|
||||
*/
|
||||
private static final int OLD_CREATE_BUTTON_TITLE_RES_ID =
|
||||
Utils.getResourceIdentifier("bottom_navigation_bar_create_tab_title", "string");
|
||||
|
||||
/**
|
||||
* Injection point. This method is called on every navigation bar item to check whether it is the Create button.
|
||||
* If the navigation bar item is the Create button, it returns null to erase it.
|
||||
* The method fingerprint used to patch ensures we can safely return null here.
|
||||
*/
|
||||
public static Object returnNullIfIsCreateButton(Object navigationBarItem) {
|
||||
if (navigationBarItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String stringifiedNavigationBarItem = navigationBarItem.toString();
|
||||
boolean isCreateButton = CREATE_BUTTON_TITLE_RES_ID_LIST.stream()
|
||||
.anyMatch(stringifiedNavigationBarItem::contains);
|
||||
|
||||
if (isCreateButton) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return navigationBarItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point. Called in older versions of the app. Returns whether the old navigation bar item is the old
|
||||
* Create button.
|
||||
*/
|
||||
public static boolean isOldCreateButton(int oldNavigationBarItemTitleResId) {
|
||||
return oldNavigationBarItemTitleResId == OLD_CREATE_BUTTON_TITLE_RES_ID;
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class UnlockPremiumPatch {
|
||||
@ -22,15 +23,15 @@ public final class UnlockPremiumPatch {
|
||||
private static final boolean IS_SPOTIFY_LEGACY_APP_TARGET;
|
||||
|
||||
static {
|
||||
boolean legacy;
|
||||
boolean isLegacy;
|
||||
try {
|
||||
Class.forName(SPOTIFY_MAIN_ACTIVITY_LEGACY);
|
||||
legacy = true;
|
||||
isLegacy = true;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
legacy = false;
|
||||
isLegacy = false;
|
||||
}
|
||||
|
||||
IS_SPOTIFY_LEGACY_APP_TARGET = legacy;
|
||||
IS_SPOTIFY_LEGACY_APP_TARGET = isLegacy;
|
||||
}
|
||||
|
||||
private static class OverrideAttribute {
|
||||
@ -61,11 +62,12 @@ public final class UnlockPremiumPatch {
|
||||
}
|
||||
}
|
||||
|
||||
private static final List<OverrideAttribute> OVERRIDES = List.of(
|
||||
private static final List<OverrideAttribute> PREMIUM_OVERRIDES = List.of(
|
||||
// Disables player and app ads.
|
||||
new OverrideAttribute("ads", FALSE),
|
||||
// Works along on-demand, allows playing any song without restriction.
|
||||
new OverrideAttribute("player-license", "premium"),
|
||||
new OverrideAttribute("player-license-v2", "premium", !IS_SPOTIFY_LEGACY_APP_TARGET),
|
||||
// Disables shuffle being initially enabled when first playing a playlist.
|
||||
new OverrideAttribute("shuffle", FALSE),
|
||||
// Allows playing any song on-demand, without a shuffled order.
|
||||
@ -91,18 +93,46 @@ public final class UnlockPremiumPatch {
|
||||
new OverrideAttribute("tablet-free", FALSE, false)
|
||||
);
|
||||
|
||||
/**
|
||||
* A list of home sections feature types ids which should be removed. These ids match the ones from the protobuf
|
||||
* response which delivers home sections.
|
||||
*/
|
||||
private static final List<Integer> REMOVED_HOME_SECTIONS = List.of(
|
||||
Section.VIDEO_BRAND_AD_FIELD_NUMBER,
|
||||
Section.IMAGE_BRAND_AD_FIELD_NUMBER
|
||||
);
|
||||
|
||||
/**
|
||||
* A list of lists which contain strings that match whether a context menu item should be filtered out.
|
||||
* The main approach used is matching context menu items by the id of their text resource.
|
||||
*/
|
||||
private static final List<List<String>> FILTERED_CONTEXT_MENU_ITEMS_BY_STRINGS = List.of(
|
||||
// "Listen to music ad-free" upsell on playlists.
|
||||
List.of(getResourceIdentifier("context_menu_remove_ads")),
|
||||
// "Listen to music ad-free" upsell on albums.
|
||||
List.of(getResourceIdentifier("playlist_entity_reinventfree_adsfree_context_menu_item")),
|
||||
// "Start a Jam" context menu item, but only filtered if the user does not have premium and the item is
|
||||
// being used as a Premium upsell (ad).
|
||||
List.of(
|
||||
getResourceIdentifier("group_session_context_menu_start"),
|
||||
"isPremiumUpsell=true"
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Utility method for returning resources ids as strings.
|
||||
*/
|
||||
private static String getResourceIdentifier(String resourceIdentifierName) {
|
||||
return Integer.toString(Utils.getResourceIdentifier(resourceIdentifierName, "id"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point. Override account attributes.
|
||||
*/
|
||||
public static void overrideAttribute(Map<String, /*AccountAttribute*/ Object> attributes) {
|
||||
public static void overrideAttributes(Map<String, /*AccountAttribute*/ Object> attributes) {
|
||||
try {
|
||||
for (var override : OVERRIDES) {
|
||||
var attribute = attributes.get(override.key);
|
||||
for (OverrideAttribute override : PREMIUM_OVERRIDES) {
|
||||
Object attribute = attributes.get(override.key);
|
||||
if (attribute == null) {
|
||||
if (override.isExpected) {
|
||||
Logger.printException(() -> "'" + override.key + "' expected but not found");
|
||||
@ -117,12 +147,12 @@ public final class UnlockPremiumPatch {
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "overrideAttribute failure", ex);
|
||||
Logger.printException(() -> "overrideAttributes failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point. Remove station data from Google assistant URI.
|
||||
* Injection point. Remove station data from Google Assistant URI.
|
||||
*/
|
||||
public static String removeStationString(String spotifyUriOrUrl) {
|
||||
return spotifyUriOrUrl.replace("spotify:station:", "spotify:");
|
||||
@ -130,7 +160,7 @@ public final class UnlockPremiumPatch {
|
||||
|
||||
/**
|
||||
* Injection point. Remove ads sections from home.
|
||||
* Depends on patching protobuffer list remove method.
|
||||
* Depends on patching abstract protobuf list ensureIsMutable method.
|
||||
*/
|
||||
public static void removeHomeSections(List<Section> sections) {
|
||||
try {
|
||||
@ -139,4 +169,17 @@ public final class UnlockPremiumPatch {
|
||||
Logger.printException(() -> "Remove home sections failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point. Returns whether the context menu item is a Premium ad.
|
||||
*/
|
||||
public static boolean isFilteredContextMenuItem(Object contextMenuItem) {
|
||||
if (contextMenuItem == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String stringifiedContextMenuItem = contextMenuItem.toString();
|
||||
return FILTERED_CONTEXT_MENU_ITEMS_BY_STRINGS.stream()
|
||||
.anyMatch(filters -> filters.stream().allMatch(stringifiedContextMenuItem::contains));
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,11 @@ android {
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 26
|
||||
minSdk = 24
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user