refactor(Spotify): Add extensions debug logging (#5110)

This commit is contained in:
Nuckyz
2025-06-05 16:04:02 -03:00
committed by GitHub
parent 617d925fcf
commit f2ca0eeac0
10 changed files with 101 additions and 27 deletions

View File

@ -6,7 +6,7 @@ dependencies {
android { android {
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 21
} }
compileOptions { compileOptions {

View File

@ -2,6 +2,7 @@ package app.revanced.extension.spotify.layout.hide.createbutton;
import java.util.List; import java.util.List;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -31,10 +32,21 @@ public final class HideCreateButtonPatch {
} }
String stringifiedNavigationBarItem = navigationBarItem.toString(); String stringifiedNavigationBarItem = navigationBarItem.toString();
boolean isCreateButton = CREATE_BUTTON_TITLE_RES_ID_LIST.stream()
.anyMatch(stringifiedNavigationBarItem::contains); boolean isCreateButton = false;
String matchedTitleResId = null;
for (String titleResId : CREATE_BUTTON_TITLE_RES_ID_LIST) {
if (stringifiedNavigationBarItem.contains(titleResId)) {
isCreateButton = true;
matchedTitleResId = titleResId;
}
}
if (isCreateButton) { if (isCreateButton) {
String finalMatchedTitleResId = matchedTitleResId;
Logger.printInfo(() -> "Hiding Create button because the navigation bar item " + navigationBarItem +
" matched the title resource id " + finalMatchedTitleResId);
return null; return null;
} }
@ -46,6 +58,14 @@ public final class HideCreateButtonPatch {
* Create button. * Create button.
*/ */
public static boolean isOldCreateButton(int oldNavigationBarItemTitleResId) { public static boolean isOldCreateButton(int oldNavigationBarItemTitleResId) {
return oldNavigationBarItemTitleResId == OLD_CREATE_BUTTON_TITLE_RES_ID; boolean isCreateButton = oldNavigationBarItemTitleResId == OLD_CREATE_BUTTON_TITLE_RES_ID;
if (isCreateButton) {
Logger.printInfo(() -> "Hiding old Create button because the navigation bar item title resource id" +
" matched " + OLD_CREATE_BUTTON_TITLE_RES_ID);
return true;
}
return false;
} }
} }

View File

@ -5,6 +5,7 @@ import static java.lang.Boolean.TRUE;
import com.spotify.home.evopage.homeapi.proto.Section; import com.spotify.home.evopage.homeapi.proto.Section;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -133,17 +134,33 @@ public final class UnlockPremiumPatch {
try { try {
for (OverrideAttribute override : PREMIUM_OVERRIDES) { for (OverrideAttribute override : PREMIUM_OVERRIDES) {
Object attribute = attributes.get(override.key); Object attribute = attributes.get(override.key);
if (attribute == null) { if (attribute == null) {
if (override.isExpected) { if (override.isExpected) {
Logger.printException(() -> "'" + override.key + "' expected but not found"); Logger.printException(() -> "Attribute " + override.key + " expected but not found");
} }
continue;
}
Object overrideValue = override.overrideValue;
Object originalValue;
if (IS_SPOTIFY_LEGACY_APP_TARGET) {
originalValue = ((com.spotify.useraccount.v1.AccountAttribute) attribute).value_;
} else { } else {
Object overrideValue = override.overrideValue; originalValue = ((com.spotify.remoteconfig.internal.AccountAttribute) attribute).value_;
if (IS_SPOTIFY_LEGACY_APP_TARGET) { }
((com.spotify.useraccount.v1.AccountAttribute) attribute).value_ = overrideValue;
} else { if (overrideValue == originalValue) {
((com.spotify.remoteconfig.internal.AccountAttribute) attribute).value_ = overrideValue; continue;
} }
Logger.printInfo(() -> "Overriding account attribute " + override.key +
" from " + originalValue + " to " + overrideValue);
if (IS_SPOTIFY_LEGACY_APP_TARGET) {
((com.spotify.useraccount.v1.AccountAttribute) attribute).value_ = overrideValue;
} else {
((com.spotify.remoteconfig.internal.AccountAttribute) attribute).value_ = overrideValue;
} }
} }
} catch (Exception ex) { } catch (Exception ex) {
@ -155,7 +172,13 @@ public final class UnlockPremiumPatch {
* Injection point. Remove station data from Google Assistant URI. * Injection point. Remove station data from Google Assistant URI.
*/ */
public static String removeStationString(String spotifyUriOrUrl) { public static String removeStationString(String spotifyUriOrUrl) {
return spotifyUriOrUrl.replace("spotify:station:", "spotify:"); try {
Logger.printInfo(() -> "Removing station string from " + spotifyUriOrUrl);
return spotifyUriOrUrl.replace("spotify:station:", "spotify:");
} catch (Exception ex) {
Logger.printException(() -> "removeStationString failure", ex);
return spotifyUriOrUrl;
}
} }
/** /**
@ -164,9 +187,17 @@ public final class UnlockPremiumPatch {
*/ */
public static void removeHomeSections(List<Section> sections) { public static void removeHomeSections(List<Section> sections) {
try { try {
sections.removeIf(section -> REMOVED_HOME_SECTIONS.contains(section.featureTypeCase_)); Iterator<Section> iterator = sections.iterator();
while (iterator.hasNext()) {
Section section = iterator.next();
if (REMOVED_HOME_SECTIONS.contains(section.featureTypeCase_)) {
Logger.printInfo(() -> "Removing home section with feature type id " + section.featureTypeCase_);
iterator.remove();
}
}
} catch (Exception ex) { } catch (Exception ex) {
Logger.printException(() -> "Remove home sections failure", ex); Logger.printException(() -> "removeHomeSections failure", ex);
} }
} }
@ -179,7 +210,30 @@ public final class UnlockPremiumPatch {
} }
String stringifiedContextMenuItem = contextMenuItem.toString(); String stringifiedContextMenuItem = contextMenuItem.toString();
return FILTERED_CONTEXT_MENU_ITEMS_BY_STRINGS.stream() for (List<String> stringList : FILTERED_CONTEXT_MENU_ITEMS_BY_STRINGS) {
.anyMatch(filters -> filters.stream().allMatch(stringifiedContextMenuItem::contains)); boolean allMatch = true;
StringBuilder matchedStrings = new StringBuilder();
for (int i = 0; i < stringList.size(); i++) {
String string = stringList.get(i);
if (!stringifiedContextMenuItem.contains(string)) {
allMatch = false;
break;
}
matchedStrings.append(string);
if (i < stringList.size() - 1) {
matchedStrings.append(", ");
}
}
if (allMatch) {
Logger.printInfo(() -> "Filtering context menu item " + stringifiedContextMenuItem +
" because the following strings matched: " + matchedStrings);
return true;
}
}
return false;
} }
} }

View File

@ -33,10 +33,11 @@ public final class SanitizeSharingLinksPatch {
} }
} }
return builder.build().toString(); String sanitizedUrl = builder.build().toString();
Logger.printInfo(() -> "Sanitized url " + url + " to " + sanitizedUrl);
return sanitizedUrl;
} catch (Exception ex) { } catch (Exception ex) {
Logger.printException(() -> "sanitizeUrl failure", ex); Logger.printException(() -> "sanitizeUrl failure with " + url, ex);
return url; return url;
} }
} }

View File

@ -7,7 +7,7 @@ android {
compileSdk = 34 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 21
} }
compileOptions { compileOptions {

View File

@ -72,7 +72,7 @@ val hideCreateButtonPatch = bytecodePatch(
if (oldNavigationBarAddItemMethod != null) { if (oldNavigationBarAddItemMethod != null) {
// In case an older version of the app is being patched, hook the old method which adds navigation bar items. // In case an older version of the app is being patched, hook the old method which adds navigation bar items.
// Return null early if the navigation bar item title resource id is old Create button title resource id. // Return null early if the navigation bar item title resource id is the old Create button title resource id.
oldNavigationBarAddItemFingerprint.methodOrNull?.apply { oldNavigationBarAddItemFingerprint.methodOrNull?.apply {
val getNavigationBarItemTitleStringIndex = indexOfFirstInstructionOrThrow { val getNavigationBarItemTitleStringIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>() val reference = getReference<MethodReference>()

View File

@ -129,7 +129,7 @@ val customThemePatch = resourcePatch(
val accentColorPressed by stringOption( val accentColorPressed by stringOption(
key = "accentColorPressed", key = "accentColorPressed",
default = "#FF1ABC54", default = "#FF1ABC54",
title = "Pressed dark theme accent color", title = "Pressed accent color",
description = "The color when accented buttons are pressed, by default slightly darker than accent. " + description = "The color when accented buttons are pressed, by default slightly darker than accent. " +
"Can be a hex color or a resource reference.", "Can be a hex color or a resource reference.",
required = true, required = true,

View File

@ -38,7 +38,7 @@ val unlockPremiumPatch = bytecodePatch(
// so for now this is a dependent of this patch. // so for now this is a dependent of this patch.
// //
// FIXME: Modifying string resources (such as adding patch strings) // FIXME: Modifying string resources (such as adding patch strings)
// is currently failing with ReVanced manager. // is currently failing with ReVanced Manager.
// checkEnvironmentPatch, // checkEnvironmentPatch,
) )
@ -78,7 +78,7 @@ val unlockPremiumPatch = bytecodePatch(
if (IS_SPOTIFY_LEGACY_APP_TARGET) { if (IS_SPOTIFY_LEGACY_APP_TARGET) {
Logger.getLogger(this::class.java.name).warning( Logger.getLogger(this::class.java.name).warning(
"Patching a legacy Spotify version. Patch functionality may be limited." "Patching a legacy Spotify version. Patch functionality may be limited."
) )
return@execute return@execute
} }
@ -174,7 +174,7 @@ val unlockPremiumPatch = bytecodePatch(
// Need to allow mutation of the list so the home ads sections can be removed. // Need to allow mutation of the list so the home ads sections can be removed.
// Protobuf array list has an 'isMutable' boolean parameter that sets the mutability. // Protobuf array list has an 'isMutable' boolean parameter that sets the mutability.
// Forcing that always on breaks unrelated code in strange ways. // Forcing that always on breaks unrelated code in strange ways.
// Instead, return early in the method that throws an error if the list is unmutable. // Instead, return early in the method that throws an error if the list is immutable.
abstractProtobufListEnsureIsMutableFingerprint.match(abstractProtobufListClassDef) abstractProtobufListEnsureIsMutableFingerprint.match(abstractProtobufListClassDef)
.method.returnEarly() .method.returnEarly()

View File

@ -15,7 +15,7 @@ val fixFacebookLoginPatch = bytecodePatch(
// The Facebook SDK tries to handle the login using the Facebook app in case it is installed. // The Facebook SDK tries to handle the login using the Facebook app in case it is installed.
// However, the Facebook app does signature checks with the app that is requesting the authentication, // However, the Facebook app does signature checks with the app that is requesting the authentication,
// which ends up making the Facebook server reject with an invalid key hash for the app signature. // which ends up making the Facebook server reject with an invalid key hash for the app signature.
// Override the Faceboook SDK to always handle the login using the web browser, which does not perform // Override the Facebook SDK to always handle the login using the web browser, which does not perform
// signature checks. // signature checks.
val katanaProxyLoginMethodHandlerClass = katanaProxyLoginMethodHandlerClassFingerprint.originalClassDef val katanaProxyLoginMethodHandlerClass = katanaProxyLoginMethodHandlerClassFingerprint.originalClassDef

View File

@ -1,7 +1,6 @@
package app.revanced.patches.spotify.misc.widgets package app.revanced.patches.spotify.misc.widgets
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal val canBindAppWidgetPermissionFingerprint = fingerprint { internal val canBindAppWidgetPermissionFingerprint = fingerprint {