From e018c33bed33c45e247b14b726a9b34c5b97f79e Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Mon, 7 Apr 2025 16:57:04 +0200 Subject: [PATCH 01/13] fix(Spotify - Unlock premium): Add limited support for legacy app target 8.6.98.900 --- .../spotify/misc/UnlockPremiumPatch.java | 29 +++++++++++++++---- .../useraccount/v1/AccountAttribute.java | 8 +++++ .../patches/spotify/misc/Fingerprints.kt | 8 +++-- .../spotify/misc/UnlockPremiumPatch.kt | 7 +++++ .../patches/spotify/misc/extension/Hooks.kt | 4 +-- 5 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java diff --git a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java index e58afe575e..28e25d0330 100644 --- a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java +++ b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java @@ -3,7 +3,6 @@ import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; -import com.spotify.remoteconfig.internal.AccountAttribute; import com.spotify.home.evopage.homeapi.proto.Section; import java.util.List; @@ -15,6 +14,21 @@ @SuppressWarnings("unused") public final class UnlockPremiumPatch { + /** + * If the app is target 8.6.98.900. + */ + private static final boolean USING_LEGACY_APP_TARGET; + static { + boolean legacyClassFound; + try { + Class.forName("com.spotify.useraccount.v1.AccountAttribute"); + legacyClassFound = true; + } catch (ClassNotFoundException ex) { + legacyClassFound = false; + } + USING_LEGACY_APP_TARGET = legacyClassFound; + } + private static class OverrideAttribute { /** * Account attribute key. @@ -55,8 +69,8 @@ private static class OverrideAttribute { // Make sure playing songs is not disabled remotely and playlists show up. new OverrideAttribute("streaming", TRUE), // Allows adding songs to queue and removes the smart shuffle mode restriction, - // allowing to pick any of the other modes. - new OverrideAttribute("pick-and-shuffle", FALSE), + // allowing to pick any of the other modes. Flag is not present in legacy app target. + new OverrideAttribute("pick-and-shuffle", FALSE, !USING_LEGACY_APP_TARGET), // Disables shuffle-mode streaming-rule, which forces songs to be played shuffled // and breaks the player when other patches are applied. new OverrideAttribute("streaming-rules", ""), @@ -78,7 +92,7 @@ private static class OverrideAttribute { /** * Override attributes injection point. */ - public static void overrideAttribute(Map attributes) { + public static void overrideAttribute(Map attributes) { try { for (var override : OVERRIDES) { var attribute = attributes.get(override.key); @@ -87,7 +101,12 @@ public static void overrideAttribute(Map attributes) { Logger.printException(() -> "'" + override.key + "' expected but not found"); } } else { - attribute.value_ = override.overrideValue; + Object overrideValue = override.overrideValue; + if (USING_LEGACY_APP_TARGET) { + ((com.spotify.useraccount.v1.AccountAttribute) attribute).value_ = overrideValue; + } else { + ((com.spotify.remoteconfig.internal.AccountAttribute) attribute).value_ = overrideValue; + } } } } catch (Exception ex) { diff --git a/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java b/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java new file mode 100644 index 0000000000..ceec870e90 --- /dev/null +++ b/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java @@ -0,0 +1,8 @@ +package com.spotify.useraccount.v1; + +/** + * Target 8.6.98.900. + */ +public class AccountAttribute { + public Object value_; +} diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt index b23f405f4f..132be7a396 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt @@ -5,12 +5,16 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode internal val accountAttributeFingerprint = fingerprint { - custom { _, classDef -> classDef.endsWith("internal/AccountAttribute;") } + custom { _, classDef -> classDef.endsWith("/AccountAttribute;") } } internal val productStateProtoFingerprint = fingerprint { returns("Ljava/util/Map;") - custom { _, classDef -> classDef.endsWith("ProductStateProto;") } + custom { _, classDef -> + classDef.endsWith("/ProductStateProto;") + // Legacy app target 8.6.98.900 + || classDef.type == "Lcom/spotify/ucs/proto/v0/UcsResponseWrapper${'$'}AccountAttributesResponse;" + } } internal val buildQueryParametersFingerprint = fingerprint { diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt index eee224f17d..eaae80e5f1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt @@ -14,6 +14,7 @@ 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 java.util.logging.Logger private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/spotify/misc/UnlockPremiumPatch;" @@ -53,6 +54,12 @@ val unlockPremiumPatch = bytecodePatch( method.replaceInstruction(addQueryParameterConditionIndex, "nop") } + if (classes.find { it.type == "Lcom/spotify/useraccount/v1/AccountAttribute;" } != null) { + return@execute Logger.getLogger(this::class.java.name).warning( + "Patching a legacy app target and patch may have limited functionality." + ) + } + // Disable the "Spotify Premium" upsell experiment in context menus. with(contextMenuExperimentsFingerprint) { val moveIsEnabledIndex = method.indexOfFirstInstructionOrThrow( 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 baed926eac..51f479921e 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 @@ -4,7 +4,7 @@ import app.revanced.patches.shared.misc.extension.extensionHook internal val spotifyMainActivityOnCreate = extensionHook { custom { method, classDef -> - classDef.type == "Lcom/spotify/music/SpotifyMainActivity;" && - method.name == "onCreate" + method.name == "onCreate" && (classDef.type == "Lcom/spotify/music/SpotifyMainActivity;" + || classDef.type == "Lcom/spotify/music/MainActivity;") // target 8.6.98.900 } } From 633cbc411f693bc6cabf1af29c18ac9700bd7cd9 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Mon, 7 Apr 2025 18:07:33 +0200 Subject: [PATCH 02/13] fix detecting target 8.6.98.900 --- .../spotify/misc/UnlockPremiumPatch.java | 19 ++++++++++--------- .../useraccount/v1/AccountAttribute.java | 2 +- .../patches/spotify/misc/Fingerprints.kt | 2 +- .../spotify/misc/UnlockPremiumPatch.kt | 5 +++-- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java index 28e25d0330..2dd40a43da 100644 --- a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java +++ b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java @@ -15,18 +15,19 @@ public final class UnlockPremiumPatch { /** - * If the app is target 8.6.98.900. + * If the app is target is not 8.6.98.900. */ - private static final boolean USING_LEGACY_APP_TARGET; + private static final boolean USING_NON_LEGACY_APP_TARGET; static { - boolean legacyClassFound; + boolean nonLegacy; try { - Class.forName("com.spotify.useraccount.v1.AccountAttribute"); - legacyClassFound = true; + Class.forName("com.spotify.remoteconfig.internal.AccountAttribute"); + nonLegacy = false; } catch (ClassNotFoundException ex) { - legacyClassFound = false; + nonLegacy = true; } - USING_LEGACY_APP_TARGET = legacyClassFound; + + USING_NON_LEGACY_APP_TARGET = nonLegacy; } private static class OverrideAttribute { @@ -70,7 +71,7 @@ private static class OverrideAttribute { new OverrideAttribute("streaming", TRUE), // Allows adding songs to queue and removes the smart shuffle mode restriction, // allowing to pick any of the other modes. Flag is not present in legacy app target. - new OverrideAttribute("pick-and-shuffle", FALSE, !USING_LEGACY_APP_TARGET), + new OverrideAttribute("pick-and-shuffle", FALSE, !USING_NON_LEGACY_APP_TARGET), // Disables shuffle-mode streaming-rule, which forces songs to be played shuffled // and breaks the player when other patches are applied. new OverrideAttribute("streaming-rules", ""), @@ -102,7 +103,7 @@ public static void overrideAttribute(Map at } } else { Object overrideValue = override.overrideValue; - if (USING_LEGACY_APP_TARGET) { + if (USING_NON_LEGACY_APP_TARGET) { ((com.spotify.useraccount.v1.AccountAttribute) attribute).value_ = overrideValue; } else { ((com.spotify.remoteconfig.internal.AccountAttribute) attribute).value_ = overrideValue; diff --git a/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java b/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java index ceec870e90..bcee67a2d8 100644 --- a/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java +++ b/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java @@ -1,7 +1,7 @@ package com.spotify.useraccount.v1; /** - * Target 8.6.98.900. + * Used for target 8.6.98.900. Class is still present in newer app targets. */ public class AccountAttribute { public Object value_; diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt index 132be7a396..ec7792f663 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt @@ -12,7 +12,7 @@ internal val productStateProtoFingerprint = fingerprint { returns("Ljava/util/Map;") custom { _, classDef -> classDef.endsWith("/ProductStateProto;") - // Legacy app target 8.6.98.900 + // Legacy app target 8.6.98.900. || classDef.type == "Lcom/spotify/ucs/proto/v0/UcsResponseWrapper${'$'}AccountAttributesResponse;" } } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt index eaae80e5f1..fceb3289c7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt @@ -54,9 +54,10 @@ val unlockPremiumPatch = bytecodePatch( method.replaceInstruction(addQueryParameterConditionIndex, "nop") } - if (classes.find { it.type == "Lcom/spotify/useraccount/v1/AccountAttribute;" } != null) { + // Check if patching 8.6.98.900. + if (classes.find { it.type == "Lcom/spotify/remoteconfig/internal/AccountAttribute;" } == null) { return@execute Logger.getLogger(this::class.java.name).warning( - "Patching a legacy app target and patch may have limited functionality." + "Using a legacy app target and patch functionality may be limited." ) } From 95cd75290435cb1991bfcaae64be2eab54d9f1d9 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Mon, 7 Apr 2025 18:13:16 +0200 Subject: [PATCH 03/13] refactor --- .../app/revanced/patches/spotify/misc/Fingerprints.kt | 11 ++++++++++- .../patches/spotify/misc/UnlockPremiumPatch.kt | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt index ec7792f663..e3375f8c53 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt @@ -4,8 +4,17 @@ import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +internal const val SPOTIFY_ACCOUNT_ATTRIBUTE = "Lcom/spotify/remoteconfig/internal/AccountAttribute;" + +/** + * Version 8.6.98.900. + */ +internal const val SPOTIFY_ACCOUNT_ATTRIBUTE_LEGACY = "Lcom/spotify/useraccount/v1/AccountAttribute;" + internal val accountAttributeFingerprint = fingerprint { - custom { _, classDef -> classDef.endsWith("/AccountAttribute;") } + custom { _, classDef -> + classDef.type == SPOTIFY_ACCOUNT_ATTRIBUTE || classDef.type == SPOTIFY_ACCOUNT_ATTRIBUTE_LEGACY + } } internal val productStateProtoFingerprint = fingerprint { diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt index fceb3289c7..bf7cb13622 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt @@ -55,7 +55,7 @@ val unlockPremiumPatch = bytecodePatch( } // Check if patching 8.6.98.900. - if (classes.find { it.type == "Lcom/spotify/remoteconfig/internal/AccountAttribute;" } == null) { + if (classes.find { it.type == SPOTIFY_ACCOUNT_ATTRIBUTE } == null) { return@execute Logger.getLogger(this::class.java.name).warning( "Using a legacy app target and patch functionality may be limited." ) From bebd057cc4a5cbf1a84f0dd9f6ddba98058d1296 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Mon, 7 Apr 2025 18:18:00 +0200 Subject: [PATCH 04/13] refactor --- .../spotify/misc/UnlockPremiumPatch.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java index 2dd40a43da..19dff968f5 100644 --- a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java +++ b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java @@ -15,19 +15,19 @@ public final class UnlockPremiumPatch { /** - * If the app is target is not 8.6.98.900. + * If the app is target is 8.6.98.900. */ - private static final boolean USING_NON_LEGACY_APP_TARGET; + private static final boolean USING_LEGACY_APP_TARGET; static { - boolean nonLegacy; + boolean legacy; try { Class.forName("com.spotify.remoteconfig.internal.AccountAttribute"); - nonLegacy = false; + legacy = false; } catch (ClassNotFoundException ex) { - nonLegacy = true; + legacy = true; } - USING_NON_LEGACY_APP_TARGET = nonLegacy; + USING_LEGACY_APP_TARGET = legacy; } private static class OverrideAttribute { @@ -71,7 +71,7 @@ private static class OverrideAttribute { new OverrideAttribute("streaming", TRUE), // Allows adding songs to queue and removes the smart shuffle mode restriction, // allowing to pick any of the other modes. Flag is not present in legacy app target. - new OverrideAttribute("pick-and-shuffle", FALSE, !USING_NON_LEGACY_APP_TARGET), + new OverrideAttribute("pick-and-shuffle", FALSE, !USING_LEGACY_APP_TARGET), // Disables shuffle-mode streaming-rule, which forces songs to be played shuffled // and breaks the player when other patches are applied. new OverrideAttribute("streaming-rules", ""), @@ -103,7 +103,7 @@ public static void overrideAttribute(Map at } } else { Object overrideValue = override.overrideValue; - if (USING_NON_LEGACY_APP_TARGET) { + if (USING_LEGACY_APP_TARGET) { ((com.spotify.useraccount.v1.AccountAttribute) attribute).value_ = overrideValue; } else { ((com.spotify.remoteconfig.internal.AccountAttribute) attribute).value_ = overrideValue; From c7f3ace967d09d839df9e2047453fa382cf1324b Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Mon, 7 Apr 2025 18:24:16 +0200 Subject: [PATCH 05/13] Fix potential matching old attribute in newer targets --- .../app/revanced/patches/spotify/misc/Fingerprints.kt | 6 +++++- .../patches/spotify/misc/UnlockPremiumPatch.kt | 11 +++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt index e3375f8c53..9c5ea79a76 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt @@ -13,7 +13,11 @@ internal const val SPOTIFY_ACCOUNT_ATTRIBUTE_LEGACY = "Lcom/spotify/useraccount/ internal val accountAttributeFingerprint = fingerprint { custom { _, classDef -> - classDef.type == SPOTIFY_ACCOUNT_ATTRIBUTE || classDef.type == SPOTIFY_ACCOUNT_ATTRIBUTE_LEGACY + if (SPOTIFY_LEGACY_APP_TARGET) { + classDef.type == SPOTIFY_ACCOUNT_ATTRIBUTE_LEGACY + } else { + classDef.type == SPOTIFY_ACCOUNT_ATTRIBUTE + } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt index bf7cb13622..2746c67eae 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt @@ -18,6 +18,11 @@ import java.util.logging.Logger private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/spotify/misc/UnlockPremiumPatch;" +/** + * If patching 8.6.98.900. + */ +internal var SPOTIFY_LEGACY_APP_TARGET = false + @Suppress("unused") val unlockPremiumPatch = bytecodePatch( name = "Unlock Spotify Premium", @@ -28,6 +33,9 @@ val unlockPremiumPatch = bytecodePatch( dependsOn(sharedExtensionPatch) execute { + // Check if patching 8.6.98.900. + SPOTIFY_LEGACY_APP_TARGET = (classes.find { it.type == SPOTIFY_ACCOUNT_ATTRIBUTE } == null) + // Make _value accessible so that it can be overridden in the extension. accountAttributeFingerprint.classDef.fields.first { it.name == "value_" }.apply { // Add public flag and remove private. @@ -54,8 +62,7 @@ val unlockPremiumPatch = bytecodePatch( method.replaceInstruction(addQueryParameterConditionIndex, "nop") } - // Check if patching 8.6.98.900. - if (classes.find { it.type == SPOTIFY_ACCOUNT_ATTRIBUTE } == null) { + if (SPOTIFY_LEGACY_APP_TARGET) { return@execute Logger.getLogger(this::class.java.name).warning( "Using a legacy app target and patch functionality may be limited." ) From 4f07c9205e174a0e79c2f501317681fab9d7f5b5 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Mon, 7 Apr 2025 18:27:33 +0200 Subject: [PATCH 06/13] refactor --- .../patches/spotify/misc/Fingerprints.kt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt index 9c5ea79a76..8a20b09836 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt @@ -9,14 +9,14 @@ internal const val SPOTIFY_ACCOUNT_ATTRIBUTE = "Lcom/spotify/remoteconfig/intern /** * Version 8.6.98.900. */ -internal const val SPOTIFY_ACCOUNT_ATTRIBUTE_LEGACY = "Lcom/spotify/useraccount/v1/AccountAttribute;" +private const val SPOTIFY_ACCOUNT_ATTRIBUTE_LEGACY = "Lcom/spotify/useraccount/v1/AccountAttribute;" internal val accountAttributeFingerprint = fingerprint { custom { _, classDef -> - if (SPOTIFY_LEGACY_APP_TARGET) { - classDef.type == SPOTIFY_ACCOUNT_ATTRIBUTE_LEGACY + classDef.type == if (SPOTIFY_LEGACY_APP_TARGET) { + SPOTIFY_ACCOUNT_ATTRIBUTE_LEGACY } else { - classDef.type == SPOTIFY_ACCOUNT_ATTRIBUTE + SPOTIFY_ACCOUNT_ATTRIBUTE } } } @@ -24,9 +24,11 @@ internal val accountAttributeFingerprint = fingerprint { internal val productStateProtoFingerprint = fingerprint { returns("Ljava/util/Map;") custom { _, classDef -> - classDef.endsWith("/ProductStateProto;") - // Legacy app target 8.6.98.900. - || classDef.type == "Lcom/spotify/ucs/proto/v0/UcsResponseWrapper${'$'}AccountAttributesResponse;" + classDef.type == if (SPOTIFY_LEGACY_APP_TARGET) { + "Lcom/spotify/remoteconfig/internal/ProductStateProto;" + } else { + "Lcom/spotify/ucs/proto/v0/UcsResponseWrapper${'$'}AccountAttributesResponse;" + } } } From 85e1c868700da5cbf94fbf6ec661251fb1cf4aea Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Tue, 8 Apr 2025 00:44:51 +0200 Subject: [PATCH 07/13] fix refactoring typo --- .../revanced/extension/spotify/misc/UnlockPremiumPatch.java | 2 +- .../kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java index 19dff968f5..d25e73a40c 100644 --- a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java +++ b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java @@ -15,7 +15,7 @@ public final class UnlockPremiumPatch { /** - * If the app is target is 8.6.98.900. + * If the app target is 8.6.98.900. */ private static final boolean USING_LEGACY_APP_TARGET; static { diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt index 8a20b09836..170798c31e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt @@ -25,9 +25,9 @@ internal val productStateProtoFingerprint = fingerprint { returns("Ljava/util/Map;") custom { _, classDef -> classDef.type == if (SPOTIFY_LEGACY_APP_TARGET) { - "Lcom/spotify/remoteconfig/internal/ProductStateProto;" - } else { "Lcom/spotify/ucs/proto/v0/UcsResponseWrapper${'$'}AccountAttributesResponse;" + } else { + "Lcom/spotify/remoteconfig/internal/ProductStateProto;" } } } From 8baf5aeb7ae1c75c31bf5c65cfbb176e2006184c Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Tue, 8 Apr 2025 01:04:17 +0200 Subject: [PATCH 08/13] fix custom theme patch (bytecode changes are not needed) --- .../spotify/misc/UnlockPremiumPatch.java | 17 ++++++++++------- .../layout/theme/CustomThemeBytecodePatch.kt | 7 +++++++ .../patches/spotify/misc/Fingerprints.kt | 16 +++++----------- .../patches/spotify/misc/UnlockPremiumPatch.kt | 13 +++---------- .../spotify/misc/extension/ExtensionPatch.kt | 14 +++++++++++++- .../patches/spotify/misc/extension/Hooks.kt | 7 ++++++- 6 files changed, 44 insertions(+), 30 deletions(-) diff --git a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java index d25e73a40c..38283542f2 100644 --- a/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java +++ b/extensions/spotify/src/main/java/app/revanced/extension/spotify/misc/UnlockPremiumPatch.java @@ -14,20 +14,23 @@ @SuppressWarnings("unused") public final class UnlockPremiumPatch { + private static final String SPOTIFY_MAIN_ACTIVITY_LEGACY = "com.spotify.music.MainActivity"; + /** * If the app target is 8.6.98.900. */ - private static final boolean USING_LEGACY_APP_TARGET; + private static final boolean IS_SPOTIFY_LEGACY_APP_TARGET; + static { boolean legacy; try { - Class.forName("com.spotify.remoteconfig.internal.AccountAttribute"); - legacy = false; - } catch (ClassNotFoundException ex) { + Class.forName(SPOTIFY_MAIN_ACTIVITY_LEGACY); legacy = true; + } catch (ClassNotFoundException ex) { + legacy = false; } - USING_LEGACY_APP_TARGET = legacy; + IS_SPOTIFY_LEGACY_APP_TARGET = legacy; } private static class OverrideAttribute { @@ -71,7 +74,7 @@ private static class OverrideAttribute { new OverrideAttribute("streaming", TRUE), // Allows adding songs to queue and removes the smart shuffle mode restriction, // allowing to pick any of the other modes. Flag is not present in legacy app target. - new OverrideAttribute("pick-and-shuffle", FALSE, !USING_LEGACY_APP_TARGET), + new OverrideAttribute("pick-and-shuffle", FALSE, !IS_SPOTIFY_LEGACY_APP_TARGET), // Disables shuffle-mode streaming-rule, which forces songs to be played shuffled // and breaks the player when other patches are applied. new OverrideAttribute("streaming-rules", ""), @@ -103,7 +106,7 @@ public static void overrideAttribute(Map at } } else { Object overrideValue = override.overrideValue; - if (USING_LEGACY_APP_TARGET) { + if (IS_SPOTIFY_LEGACY_APP_TARGET) { ((com.spotify.useraccount.v1.AccountAttribute) attribute).value_ = overrideValue; } else { ((com.spotify.remoteconfig.internal.AccountAttribute) attribute).value_ = overrideValue; diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemeBytecodePatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemeBytecodePatch.kt index cdedbfd6aa..2f639ef8da 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemeBytecodePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemeBytecodePatch.kt @@ -5,6 +5,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.fingerprint import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.spotify.misc.extension.IS_SPOTIFY_LEGACY_APP_TARGET import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch import app.revanced.util.* import com.android.tools.smali.dexlib2.AccessFlags @@ -21,6 +22,12 @@ internal val customThemeByteCodePatch = bytecodePatch { val backgroundColorSecondary by spotifyBackgroundColorSecondary execute { + if (IS_SPOTIFY_LEGACY_APP_TARGET) { + // Bytecode changes are not needed for legacy app target. + // Player background color is changed with existing resource patch. + return@execute + } + fun MutableMethod.addColorChangeInstructions(literal: Long, colorString: String) { val index = indexOfFirstLiteralInstructionOrThrow(literal) val register = getInstruction(index).registerA diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt index 170798c31e..29f472a5d1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/Fingerprints.kt @@ -1,22 +1,16 @@ package app.revanced.patches.spotify.misc import app.revanced.patcher.fingerprint +import app.revanced.patches.spotify.misc.extension.IS_SPOTIFY_LEGACY_APP_TARGET import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal const val SPOTIFY_ACCOUNT_ATTRIBUTE = "Lcom/spotify/remoteconfig/internal/AccountAttribute;" - -/** - * Version 8.6.98.900. - */ -private const val SPOTIFY_ACCOUNT_ATTRIBUTE_LEGACY = "Lcom/spotify/useraccount/v1/AccountAttribute;" - internal val accountAttributeFingerprint = fingerprint { custom { _, classDef -> - classDef.type == if (SPOTIFY_LEGACY_APP_TARGET) { - SPOTIFY_ACCOUNT_ATTRIBUTE_LEGACY + classDef.type == if (IS_SPOTIFY_LEGACY_APP_TARGET) { + "Lcom/spotify/useraccount/v1/AccountAttribute;" } else { - SPOTIFY_ACCOUNT_ATTRIBUTE + "Lcom/spotify/remoteconfig/internal/AccountAttribute;" } } } @@ -24,7 +18,7 @@ internal val accountAttributeFingerprint = fingerprint { internal val productStateProtoFingerprint = fingerprint { returns("Ljava/util/Map;") custom { _, classDef -> - classDef.type == if (SPOTIFY_LEGACY_APP_TARGET) { + classDef.type == if (IS_SPOTIFY_LEGACY_APP_TARGET) { "Lcom/spotify/ucs/proto/v0/UcsResponseWrapper${'$'}AccountAttributesResponse;" } else { "Lcom/spotify/remoteconfig/internal/ProductStateProto;" diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt index 2746c67eae..658f51bfd0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt @@ -6,6 +6,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.fingerprint import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.spotify.misc.extension.IS_SPOTIFY_LEGACY_APP_TARGET import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch import app.revanced.util.* import com.android.tools.smali.dexlib2.AccessFlags @@ -18,11 +19,6 @@ import java.util.logging.Logger private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/spotify/misc/UnlockPremiumPatch;" -/** - * If patching 8.6.98.900. - */ -internal var SPOTIFY_LEGACY_APP_TARGET = false - @Suppress("unused") val unlockPremiumPatch = bytecodePatch( name = "Unlock Spotify Premium", @@ -33,9 +29,6 @@ val unlockPremiumPatch = bytecodePatch( dependsOn(sharedExtensionPatch) execute { - // Check if patching 8.6.98.900. - SPOTIFY_LEGACY_APP_TARGET = (classes.find { it.type == SPOTIFY_ACCOUNT_ATTRIBUTE } == null) - // Make _value accessible so that it can be overridden in the extension. accountAttributeFingerprint.classDef.fields.first { it.name == "value_" }.apply { // Add public flag and remove private. @@ -62,9 +55,9 @@ val unlockPremiumPatch = bytecodePatch( method.replaceInstruction(addQueryParameterConditionIndex, "nop") } - if (SPOTIFY_LEGACY_APP_TARGET) { + if (IS_SPOTIFY_LEGACY_APP_TARGET) { return@execute Logger.getLogger(this::class.java.name).warning( - "Using a legacy app target and patch functionality may be limited." + "Using a legacy app target. Patch functionality may be limited." ) } 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 6b95f437a3..e858ffb6cd 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 @@ -1,5 +1,17 @@ package app.revanced.patches.spotify.misc.extension +import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.shared.misc.extension.sharedExtensionPatch -val sharedExtensionPatch = sharedExtensionPatch("spotify", spotifyMainActivityOnCreate) +/** + * If patching 8.6.98.900. + */ +internal var IS_SPOTIFY_LEGACY_APP_TARGET = false + +val sharedExtensionPatch = bytecodePatch { + dependsOn(sharedExtensionPatch("spotify", spotifyMainActivityOnCreate)) + + execute { + IS_SPOTIFY_LEGACY_APP_TARGET = (classes.find { it.type == SPOTIFY_MAIN_ACTIVITY_LEGACY } != null) + } +} \ No newline at end of file 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 51f479921e..bf01f1dc1f 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 @@ -2,9 +2,14 @@ package app.revanced.patches.spotify.misc.extension import app.revanced.patches.shared.misc.extension.extensionHook +/** + * Main activity of target 8.6.98.900. + */ +internal const val SPOTIFY_MAIN_ACTIVITY_LEGACY = "Lcom/spotify/music/MainActivity;" + internal val spotifyMainActivityOnCreate = extensionHook { custom { method, classDef -> method.name == "onCreate" && (classDef.type == "Lcom/spotify/music/SpotifyMainActivity;" - || classDef.type == "Lcom/spotify/music/MainActivity;") // target 8.6.98.900 + || classDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY) } } From c850062700a29a9e87d176db386a614f7dca692d Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Tue, 8 Apr 2025 15:17:26 +0200 Subject: [PATCH 09/13] refactor --- .../java/com/spotify/useraccount/v1/AccountAttribute.java | 2 +- .../revanced/patches/spotify/misc/extension/ExtensionPatch.kt | 2 +- .../app/revanced/patches/spotify/misc/extension/Hooks.kt | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java b/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java index bcee67a2d8..a03b583bf5 100644 --- a/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java +++ b/extensions/spotify/stub/src/main/java/com/spotify/useraccount/v1/AccountAttribute.java @@ -1,7 +1,7 @@ package com.spotify.useraccount.v1; /** - * Used for target 8.6.98.900. Class is still present in newer app targets. + * Used for target 8.6.98.900. Class is still present in newer app targets. */ public class AccountAttribute { public Object value_; 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 e858ffb6cd..aab252e1f0 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 @@ -14,4 +14,4 @@ val sharedExtensionPatch = bytecodePatch { execute { IS_SPOTIFY_LEGACY_APP_TARGET = (classes.find { it.type == SPOTIFY_MAIN_ACTIVITY_LEGACY } != null) } -} \ No newline at end of file +} 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 bf01f1dc1f..956c5610e4 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 @@ -2,6 +2,8 @@ package app.revanced.patches.spotify.misc.extension import app.revanced.patches.shared.misc.extension.extensionHook +private const val SPOTIFY_MAIN_ACTIVITY = "Lcom/spotify/music/SpotifyMainActivity;" + /** * Main activity of target 8.6.98.900. */ @@ -9,7 +11,7 @@ internal const val SPOTIFY_MAIN_ACTIVITY_LEGACY = "Lcom/spotify/music/MainActivi internal val spotifyMainActivityOnCreate = extensionHook { custom { method, classDef -> - method.name == "onCreate" && (classDef.type == "Lcom/spotify/music/SpotifyMainActivity;" + method.name == "onCreate" && (classDef.type == SPOTIFY_MAIN_ACTIVITY || classDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY) } } From dec46f6474fb9e5b314d67a9dc1ae8a0e9af3a73 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Tue, 8 Apr 2025 15:20:42 +0200 Subject: [PATCH 10/13] comments --- .../revanced/patches/spotify/misc/extension/ExtensionPatch.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 aab252e1f0..7154a45d3c 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 @@ -4,7 +4,9 @@ import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.shared.misc.extension.sharedExtensionPatch /** - * If patching 8.6.98.900. + * If patching a legacy 8.x target. This may also be set if patching slightly older/newer app targets, + * but the only legacy target of interest is 8.6.98.900 as it's the last version that + * supports Spotify integration on Kenwood/Pioneer car stereos. */ internal var IS_SPOTIFY_LEGACY_APP_TARGET = false From e0f5f54b56f5249eef44afb6746f4a077769e363 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Wed, 9 Apr 2025 00:30:44 +0200 Subject: [PATCH 11/13] refactor --- .../patches/shared/misc/extension/SharedExtensionPatch.kt | 2 +- .../revanced/patches/spotify/misc/extension/ExtensionPatch.kt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) 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 5233f186f1..40ced06a0a 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 @@ -92,7 +92,7 @@ fun sharedExtensionPatch( } class ExtensionHook internal constructor( - private val fingerprint: Fingerprint, + internal val fingerprint: Fingerprint, private val insertIndexResolver: ((Method) -> Int), private val contextRegisterResolver: (Method) -> String, ) { 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 7154a45d3c..98afe65b22 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 @@ -14,6 +14,7 @@ val sharedExtensionPatch = bytecodePatch { dependsOn(sharedExtensionPatch("spotify", spotifyMainActivityOnCreate)) execute { - IS_SPOTIFY_LEGACY_APP_TARGET = (classes.find { it.type == SPOTIFY_MAIN_ACTIVITY_LEGACY } != null) + IS_SPOTIFY_LEGACY_APP_TARGET = spotifyMainActivityOnCreate.fingerprint + .originalClassDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY } } From 6a18a16ba62c3a68d14d3d9c475d1bf7a730f9ce Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Fri, 11 Apr 2025 21:29:10 +0200 Subject: [PATCH 12/13] fix: Use less confusing console message --- .../app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt index 658f51bfd0..e3be6306be 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt @@ -57,7 +57,7 @@ val unlockPremiumPatch = bytecodePatch( if (IS_SPOTIFY_LEGACY_APP_TARGET) { return@execute Logger.getLogger(this::class.java.name).warning( - "Using a legacy app target. Patch functionality may be limited." + "Patching a legacy Spotify version. Patch functionality may be limited." ) } From 90a088240a6170afe7b501d2ee310ed75e04ede0 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Fri, 11 Apr 2025 21:30:21 +0200 Subject: [PATCH 13/13] fix: Use info logging --- .../app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt index e3be6306be..183bbb9080 100644 --- a/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/spotify/misc/UnlockPremiumPatch.kt @@ -56,7 +56,7 @@ val unlockPremiumPatch = bytecodePatch( } if (IS_SPOTIFY_LEGACY_APP_TARGET) { - return@execute Logger.getLogger(this::class.java.name).warning( + return@execute Logger.getLogger(this::class.java.name).info( "Patching a legacy Spotify version. Patch functionality may be limited." ) }