Compare commits
4
Commits
97b4fc5b5a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
937729130f | ||
|
|
b73ca08003 | ||
|
|
42622a1bca | ||
|
|
37ef795322 |
+25
@@ -0,0 +1,25 @@
|
|||||||
|
package app.revanced.patches.spotify.premium.interceptors
|
||||||
|
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.Response
|
||||||
|
import okhttp3.Protocol
|
||||||
|
import okhttp3.Response
|
||||||
|
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||||
|
|
||||||
|
class ProductStateInterceptor : Interceptor {
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val request = chain.request()
|
||||||
|
if (request.url.encodedPath.contains("/product-state")) {
|
||||||
|
val json = "{\"product\":\"premium\",\"type\":\"premium\",\"expires\":\"2099-12-31\",\"offline\":true,\"high_bitrate\":true}"
|
||||||
|
return Response.Builder()
|
||||||
|
.request(request)
|
||||||
|
.protocol(Protocol.HTTP_1_1)
|
||||||
|
.code(200)
|
||||||
|
.message("OK")
|
||||||
|
.body(json.toResponseBody("application/json".toMediaType()))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
return chain.proceed(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
sdk.dir=/usr/lib/android-sdk
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package app.revanced.patches.spotify.misc.skip
|
||||||
|
|
||||||
|
import app.revanced.patcher.*
|
||||||
|
import app.revanced.patcher.patch.BytecodePatchContext
|
||||||
|
import app.revanced.util.literal
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
// Getter on the locally-held player Restrictions model (deserialized from local player
|
||||||
|
// state, not fetched fresh from the server per call) that lists the reasons skipping to
|
||||||
|
// the next track is currently disallowed. A free-tier account gets a non-empty set here
|
||||||
|
// once the "6 skips per hour" cap is hit, and it is also checked while an ad is playing
|
||||||
|
// to decide whether the skip button is enabled. Every skip button in the app (Now Playing
|
||||||
|
// bar, ad track, notification, etc.) reads this same getter, so overriding it to always
|
||||||
|
// report "no restrictions" removes the skip cap and unlocks skipping ads, without ever
|
||||||
|
// telling the server the account's plan changed.
|
||||||
|
internal val BytecodePatchContext.disallowSkippingNextReasonsMethod by gettingFirstMethodDeclaratively {
|
||||||
|
name("disallowSkippingNextReasons")
|
||||||
|
accessFlags(AccessFlags.PUBLIC)
|
||||||
|
parameterTypes()
|
||||||
|
// Restrictions itself only declares the getter abstractly; skip past it to the
|
||||||
|
// AutoValue-generated implementation, which is the one with an actual method body.
|
||||||
|
custom { !AccessFlags.ABSTRACT.isSet(accessFlags) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local (client-side) rapid-skip cooldown tracker: keeps the timestamps of the last 3
|
||||||
|
// skips in a LinkedList and returns 3 ("Slow down! You get 6 skips per hour.") if all 3
|
||||||
|
// happened within 10 seconds (0x2710 ms) of each other, 2 (first-ever-skip "You now have
|
||||||
|
// 6 skips per hour" toast) the very first time it's called, or 1 (no toast) otherwise.
|
||||||
|
internal val BytecodePatchContext.freeTierRapidSkipCounterMethodMatch by composingFirstMethod {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||||
|
returnType("I")
|
||||||
|
parameterTypes()
|
||||||
|
instructions(
|
||||||
|
method { name == "elapsedRealtime" && returnType == "J" },
|
||||||
|
afterAtMost(50, 10000L()),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package app.revanced.patches.spotify.misc.skip
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
|
import app.revanced.patcher.firstClassDef
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.util.returnEarly
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val removeSkipRestrictionsPatch = bytecodePatch(
|
||||||
|
name = "Remove skip restrictions",
|
||||||
|
description = "Removes the free-tier \"6 skips per hour\" limit and its toasts/upsells, " +
|
||||||
|
"and unlocks the skip button while an ad is playing. This only changes local " +
|
||||||
|
"client-side behavior; it does not report a Premium account to Spotify.",
|
||||||
|
use = false,
|
||||||
|
) {
|
||||||
|
compatibleWith("com.spotify.music")
|
||||||
|
|
||||||
|
apply {
|
||||||
|
// Force the Restrictions getter that every skip button reads to always report
|
||||||
|
// that skipping is allowed, by having it construct and return an empty instance
|
||||||
|
// of its own (obfuscated) collection return type instead of the real field.
|
||||||
|
disallowSkippingNextReasonsMethod.apply {
|
||||||
|
val emptyCollectionType = returnType
|
||||||
|
|
||||||
|
val emptyCollectionFactoryMethod = firstClassDef(emptyCollectionType).methods.first {
|
||||||
|
AccessFlags.STATIC.isSet(it.accessFlags) &&
|
||||||
|
it.returnType == emptyCollectionType &&
|
||||||
|
it.parameterTypes.map(Any::toString) == listOf("I", "[Ljava/lang/Object;")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reuses "this" (p0) as a scratch register instead of requiring a second
|
||||||
|
// local, since everything below this early return becomes dead code.
|
||||||
|
addInstructions(
|
||||||
|
0,
|
||||||
|
"""
|
||||||
|
const/4 v0, 0x0
|
||||||
|
new-array p0, v0, [Ljava/lang/Object;
|
||||||
|
invoke-static { v0, p0 }, ${emptyCollectionFactoryMethod.definingClass}->${emptyCollectionFactoryMethod.name}(I[Ljava/lang/Object;)$emptyCollectionType
|
||||||
|
move-result-object v0
|
||||||
|
return-object v0
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force the rapid-skip cooldown tracker to always behave like it does after the
|
||||||
|
// first-ever skip (return 1, no toast), instead of counting towards the cap.
|
||||||
|
freeTierRapidSkipCounterMethodMatch.method.returnEarly(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
-12
@@ -238,17 +238,27 @@ val settingsPatch = bytecodePatch(
|
|||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
"revanced_custom_hide_shorts",
|
"revanced_custom_hide_shorts",
|
||||||
),
|
),
|
||||||
ListPreference(
|
// TEMPORARILY DISABLED FOR TESTING (revanced-cli verification pass): this
|
||||||
key = "revanced_custom_default_playback_speed",
|
// ListPreference references "${key}_entries"/"${key}_entry_values" array
|
||||||
tag = "app.revanced.extension.shared.settings.preference.SortedListPreference",
|
// resources that don't exist anywhere and can't be added via addresources/
|
||||||
),
|
// values/strings.xml, since patches/strings-processing.gradle.kts only
|
||||||
|
// extracts <string> elements (see its `"string" -> transform(...)` case
|
||||||
|
// vs. the `else -> walk children` fallthrough that silently drops <array>/
|
||||||
|
// <string-array>). Needs a real app.revanced.util.resource.ArrayResource
|
||||||
|
// wired through the ListPreference(entries=, entryValues=) constructor
|
||||||
|
// (see patches/.../shared/misc/settings/preference/ListPreference.kt) or
|
||||||
|
// another array-resource source before this can ship.
|
||||||
|
// ListPreference(
|
||||||
|
// key = "revanced_custom_default_playback_speed",
|
||||||
|
// tag = "app.revanced.extension.shared.settings.preference.SortedListPreference",
|
||||||
|
// ),
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
"revanced_custom_remember_playback_speed",
|
"revanced_custom_remember_playback_speed",
|
||||||
),
|
),
|
||||||
ListPreference(
|
// ListPreference(
|
||||||
key = "revanced_custom_default_video_quality",
|
// key = "revanced_custom_default_video_quality",
|
||||||
tag = "app.revanced.extension.shared.settings.preference.SortedListPreference",
|
// tag = "app.revanced.extension.shared.settings.preference.SortedListPreference",
|
||||||
),
|
// ),
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
"revanced_custom_remember_video_quality",
|
"revanced_custom_remember_video_quality",
|
||||||
),
|
),
|
||||||
@@ -264,10 +274,10 @@ val settingsPatch = bytecodePatch(
|
|||||||
inputType = InputType.TEXT_CAP_CHARACTERS,
|
inputType = InputType.TEXT_CAP_CHARACTERS,
|
||||||
tag = "app.revanced.extension.shared.settings.preference.TextInputPreference",
|
tag = "app.revanced.extension.shared.settings.preference.TextInputPreference",
|
||||||
),
|
),
|
||||||
ListPreference(
|
// ListPreference(
|
||||||
key = "revanced_custom_startup_tab",
|
// key = "revanced_custom_startup_tab",
|
||||||
tag = "app.revanced.extension.shared.settings.preference.SortedListPreference",
|
// tag = "app.revanced.extension.shared.settings.preference.SortedListPreference",
|
||||||
),
|
// ),
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
"revanced_custom_clean_urls",
|
"revanced_custom_clean_urls",
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -241,6 +241,42 @@ However, enabling this will also log some user data such as your IP address."</s
|
|||||||
<string name="revanced_restore_old_settings_menus_title">Restore old settings menus</string>
|
<string name="revanced_restore_old_settings_menus_title">Restore old settings menus</string>
|
||||||
<string name="revanced_restore_old_settings_menus_summary_on">Old settings menus are shown</string>
|
<string name="revanced_restore_old_settings_menus_summary_on">Old settings menus are shown</string>
|
||||||
<string name="revanced_restore_old_settings_menus_summary_off">Old settings menus are not shown</string>
|
<string name="revanced_restore_old_settings_menus_summary_off">Old settings menus are not shown</string>
|
||||||
|
<!-- Custom settings -->
|
||||||
|
<string name="revanced_custom_title">Custom</string>
|
||||||
|
<string name="revanced_custom_reset_title">Reset Custom Settings</string>
|
||||||
|
<string name="revanced_custom_reset_summary">Restore custom preferences to defaults</string>
|
||||||
|
<string name="revanced_custom_force_amoled_title">Force AMOLED</string>
|
||||||
|
<string name="revanced_custom_force_amoled_summary_on">True black is used in the YouTube UI</string>
|
||||||
|
<string name="revanced_custom_force_amoled_summary_off">True black is not used in the YouTube UI</string>
|
||||||
|
<string name="revanced_custom_pure_black_player_title">Pure Black Player</string>
|
||||||
|
<string name="revanced_custom_pure_black_player_summary_on">Player background is pure black</string>
|
||||||
|
<string name="revanced_custom_pure_black_player_summary_off">Player background is not pure black</string>
|
||||||
|
<string name="revanced_custom_disable_ambient_mode_title">Disable Ambient Mode</string>
|
||||||
|
<string name="revanced_custom_disable_ambient_mode_summary_on">Ambient Mode is prevented from activating</string>
|
||||||
|
<string name="revanced_custom_disable_ambient_mode_summary_off">Ambient Mode can activate</string>
|
||||||
|
<string name="revanced_custom_hide_shorts_title">Hide Shorts</string>
|
||||||
|
<string name="revanced_custom_hide_shorts_summary_on">Shorts UI entries are removed</string>
|
||||||
|
<string name="revanced_custom_hide_shorts_summary_off">Shorts UI entries are shown</string>
|
||||||
|
<string name="revanced_custom_default_playback_speed_title">Default Playback Speed</string>
|
||||||
|
<string name="revanced_custom_remember_playback_speed_title">Remember Playback Speed</string>
|
||||||
|
<string name="revanced_custom_remember_playback_speed_summary_on">Playback speed is remembered across videos</string>
|
||||||
|
<string name="revanced_custom_remember_playback_speed_summary_off">Playback speed is not remembered across videos</string>
|
||||||
|
<string name="revanced_custom_default_video_quality_title">Default Video Quality</string>
|
||||||
|
<string name="revanced_custom_remember_video_quality_title">Remember Video Quality</string>
|
||||||
|
<string name="revanced_custom_remember_video_quality_summary_on">Video quality is remembered across videos</string>
|
||||||
|
<string name="revanced_custom_remember_video_quality_summary_off">Video quality is not remembered across videos</string>
|
||||||
|
<string name="revanced_custom_force_highest_quality_title">Force Highest Available Quality</string>
|
||||||
|
<string name="revanced_custom_force_highest_quality_summary_on">Highest quality option is preferred</string>
|
||||||
|
<string name="revanced_custom_force_highest_quality_summary_off">Highest quality option is not preferred</string>
|
||||||
|
<string name="revanced_custom_debug_video_info_title">Debug Video Information</string>
|
||||||
|
<string name="revanced_custom_debug_video_info_summary_on">Technical video details are shown</string>
|
||||||
|
<string name="revanced_custom_debug_video_info_summary_off">Technical video details are hidden</string>
|
||||||
|
<string name="revanced_custom_app_name_title">Custom App Name</string>
|
||||||
|
<string name="revanced_custom_app_name_summary">Change the visible application name</string>
|
||||||
|
<string name="revanced_custom_startup_tab_title">Default Startup Tab</string>
|
||||||
|
<string name="revanced_custom_clean_urls_title">Clean YouTube URLs</string>
|
||||||
|
<string name="revanced_custom_clean_urls_summary_on">Tracking parameters are removed from shared links</string>
|
||||||
|
<string name="revanced_custom_clean_urls_summary_off">Tracking parameters are not removed from shared links</string>
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="misc.backgroundplayback.backgroundPlaybackPatch">
|
<patch id="misc.backgroundplayback.backgroundPlaybackPatch">
|
||||||
<string name="revanced_shorts_disable_background_playback_title">Disable Shorts background play</string>
|
<string name="revanced_shorts_disable_background_playback_title">Disable Shorts background play</string>
|
||||||
@@ -1945,36 +1981,6 @@ Video playback with AV1 may stutter or drop frames."</string>
|
|||||||
<string name="revanced_twitch_debug_title">Debug logging</string>
|
<string name="revanced_twitch_debug_title">Debug logging</string>
|
||||||
<string name="revanced_twitch_debug_summary_on">Debug logs are enabled</string>
|
<string name="revanced_twitch_debug_summary_on">Debug logs are enabled</string>
|
||||||
<string name="revanced_twitch_debug_summary_off">Debug logs are disabled</string>
|
<string name="revanced_twitch_debug_summary_off">Debug logs are disabled</string>
|
||||||
<!-- Custom settings -->
|
|
||||||
<string name="revanced_custom_title">Custom</string>
|
|
||||||
<string name="revanced_custom_reset_title">Reset Custom Settings</string>
|
|
||||||
<string name="revanced_custom_reset_summary">Restore custom preferences to defaults</string>
|
|
||||||
<string name="revanced_custom_force_amoled_title">Force AMOLED</string>
|
|
||||||
<string name="revanced_custom_force_amoled_summary">Use true black in the YouTube UI</string>
|
|
||||||
<string name="revanced_custom_pure_black_player_title">Pure Black Player</string>
|
|
||||||
<string name="revanced_custom_pure_black_player_summary">Make player background pure black</string>
|
|
||||||
<string name="revanced_custom_disable_ambient_mode_title">Disable Ambient Mode</string>
|
|
||||||
<string name="revanced_custom_disable_ambient_mode_summary">Prevent Ambient Mode from activating</string>
|
|
||||||
<string name="revanced_custom_hide_shorts_title">Hide Shorts</string>
|
|
||||||
<string name="revanced_custom_hide_shorts_summary">Remove Shorts UI entries</string>
|
|
||||||
<string name="revanced_custom_default_playback_speed_title">Default Playback Speed</string>
|
|
||||||
<string name="revanced_custom_default_playback_speed_summary">Select default playback speed</string>
|
|
||||||
<string name="revanced_custom_remember_playback_speed_title">Remember Playback Speed</string>
|
|
||||||
<string name="revanced_custom_remember_playback_speed_summary">Remember speed across videos</string>
|
|
||||||
<string name="revanced_custom_default_video_quality_title">Default Video Quality</string>
|
|
||||||
<string name="revanced_custom_default_video_quality_summary">Select default video quality</string>
|
|
||||||
<string name="revanced_custom_remember_video_quality_title">Remember Video Quality</string>
|
|
||||||
<string name="revanced_custom_remember_video_quality_summary">Remember quality across videos</string>
|
|
||||||
<string name="revanced_custom_force_highest_quality_title">Force Highest Available Quality</string>
|
|
||||||
<string name="revanced_custom_force_highest_quality_summary">Prefer highest quality option</string>
|
|
||||||
<string name="revanced_custom_debug_video_info_title">Debug Video Information</string>
|
|
||||||
<string name="revanced_custom_debug_video_info_summary">Show technical video details</string>
|
|
||||||
<string name="revanced_custom_app_name_title">Custom App Name</string>
|
|
||||||
<string name="revanced_custom_app_name_summary">Change the visible application name</string>
|
|
||||||
<string name="revanced_custom_startup_tab_title">Default Startup Tab</string>
|
|
||||||
<string name="revanced_custom_startup_tab_summary">Select startup tab</string>
|
|
||||||
<string name="revanced_custom_clean_urls_title">Clean YouTube URLs</string>
|
|
||||||
<string name="revanced_custom_clean_urls_summary">Remove tracking parameters from shared links</string>
|
|
||||||
</patch>
|
</patch>
|
||||||
</app>
|
</app>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user