mirror of
https://github.com/revanced/revanced-patches
synced 2025-01-08 00:05:49 +01:00
feat(SoundCloud): Add Enable offline sync
patch (#3407)
Co-authored-by: bewzusore <bewzusore> Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de> Co-authored-by: BenCat07 <BenCat07@gitlab.com>
This commit is contained in:
parent
c3e014f7ba
commit
4de86c6407
@ -1050,6 +1050,12 @@ public final class app/revanced/patches/soundcloud/analytics/DisableTelemetryPat
|
|||||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/soundcloud/offlinesync/EnableOfflineSyncPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||||
|
public static final field INSTANCE Lapp/revanced/patches/soundcloud/offlinesync/EnableOfflineSyncPatch;
|
||||||
|
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||||
|
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/spotify/layout/theme/CustomThemePatch : app/revanced/patcher/patch/ResourcePatch {
|
public final class app/revanced/patches/spotify/layout/theme/CustomThemePatch : app/revanced/patcher/patch/ResourcePatch {
|
||||||
public static final field INSTANCE Lapp/revanced/patches/spotify/layout/theme/CustomThemePatch;
|
public static final field INSTANCE Lapp/revanced/patches/spotify/layout/theme/CustomThemePatch;
|
||||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||||
|
@ -10,7 +10,7 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage
|
|||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
import app.revanced.patches.soundcloud.ad.fingerprints.InterceptFingerprint
|
import app.revanced.patches.soundcloud.ad.fingerprints.InterceptFingerprint
|
||||||
import app.revanced.patches.soundcloud.ad.fingerprints.FeatureConstructorFingerprint
|
import app.revanced.patches.soundcloud.shared.fingerprints.FeatureConstructorFingerprint
|
||||||
import app.revanced.patches.soundcloud.ad.fingerprints.UserConsumerPlanConstructorFingerprint
|
import app.revanced.patches.soundcloud.ad.fingerprints.UserConsumerPlanConstructorFingerprint
|
||||||
import app.revanced.util.resultOrThrow
|
import app.revanced.util.resultOrThrow
|
||||||
|
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
package app.revanced.patches.soundcloud.offlinesync
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||||
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
|
import app.revanced.patches.soundcloud.offlinesync.fingerprints.DownloadOperationsHeaderVerificationFingerprint
|
||||||
|
import app.revanced.patches.soundcloud.offlinesync.fingerprints.DownloadOperationsURLBuilderFingerprint
|
||||||
|
import app.revanced.patches.soundcloud.shared.fingerprints.FeatureConstructorFingerprint
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.resultOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
|
|
||||||
|
@Patch(
|
||||||
|
name = "Enable offline sync",
|
||||||
|
compatiblePackages = [CompatiblePackage("com.soundcloud.android")],
|
||||||
|
)
|
||||||
|
@Suppress("unused")
|
||||||
|
object EnableOfflineSyncPatch : BytecodePatch(
|
||||||
|
setOf(
|
||||||
|
FeatureConstructorFingerprint, DownloadOperationsURLBuilderFingerprint,
|
||||||
|
DownloadOperationsHeaderVerificationFingerprint
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
override fun execute(context: BytecodeContext) {
|
||||||
|
// Enable the feature to allow offline track syncing by modifying the JSON server response.
|
||||||
|
// This method is the constructor of a class representing a "Feature" object parsed from JSON data.
|
||||||
|
// p1 is the name of the feature.
|
||||||
|
// p2 is true if the feature is enabled, false otherwise.
|
||||||
|
FeatureConstructorFingerprint.resultOrThrow().mutableMethod.apply {
|
||||||
|
val afterCheckNotNullIndex = 2
|
||||||
|
|
||||||
|
addInstructionsWithLabels(
|
||||||
|
afterCheckNotNullIndex,
|
||||||
|
"""
|
||||||
|
const-string v0, "offline_sync"
|
||||||
|
invoke-virtual { p1, v0 }, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
|
||||||
|
move-result v0
|
||||||
|
if-eqz v0, :skip
|
||||||
|
const/4 p2, 0x1
|
||||||
|
""",
|
||||||
|
ExternalLabel("skip", getInstruction(afterCheckNotNullIndex)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch the URL builder to use the HTTPS_STREAM endpoint
|
||||||
|
// instead of the offline sync endpoint to downloading the track.
|
||||||
|
DownloadOperationsURLBuilderFingerprint.resultOrThrow().mutableMethod.apply {
|
||||||
|
val getEndpointsEnumFieldIndex = 1
|
||||||
|
val getEndpointsEnumFieldInstruction = getInstruction<OneRegisterInstruction>(getEndpointsEnumFieldIndex)
|
||||||
|
|
||||||
|
val targetRegister = getEndpointsEnumFieldInstruction.registerA
|
||||||
|
val endpointsType = getEndpointsEnumFieldInstruction.getReference<FieldReference>()!!.type
|
||||||
|
|
||||||
|
replaceInstruction(
|
||||||
|
getEndpointsEnumFieldIndex,
|
||||||
|
"sget-object v$targetRegister, $endpointsType->HTTPS_STREAM:$endpointsType"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The HTTPS_STREAM endpoint does not return the necessary headers for offline sync.
|
||||||
|
// Mock the headers to prevent the app from crashing by setting them to empty strings.
|
||||||
|
// The headers are all cosmetic and do not affect the functionality of the app.
|
||||||
|
DownloadOperationsHeaderVerificationFingerprint.resultOrThrow().mutableMethod.apply {
|
||||||
|
// The first three null checks need to be patched.
|
||||||
|
getInstructions().asSequence().filter {
|
||||||
|
it.opcode == Opcode.IF_EQZ
|
||||||
|
}.take(3).map { it.location.index }.forEach { nullCheckIndex ->
|
||||||
|
val headerStringRegister = getInstruction<OneRegisterInstruction>(nullCheckIndex).registerA
|
||||||
|
|
||||||
|
addInstruction(nullCheckIndex, "const-string v$headerStringRegister, \"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package app.revanced.patches.soundcloud.offlinesync.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
internal object DownloadOperationsHeaderVerificationFingerprint : MethodFingerprint(
|
||||||
|
returnType = "V",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("L","L"),
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CONST_STRING
|
||||||
|
),
|
||||||
|
customFingerprint = { _, classDef ->
|
||||||
|
classDef.sourceFile == "DownloadOperations.kt"
|
||||||
|
}
|
||||||
|
)
|
@ -0,0 +1,20 @@
|
|||||||
|
package app.revanced.patches.soundcloud.offlinesync.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
internal object DownloadOperationsURLBuilderFingerprint : MethodFingerprint(
|
||||||
|
returnType = "Ljava/lang/String",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("L","L"),
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.SGET_OBJECT,
|
||||||
|
Opcode.FILLED_NEW_ARRAY
|
||||||
|
),
|
||||||
|
customFingerprint = { _, classDef ->
|
||||||
|
classDef.sourceFile == "DownloadOperations.kt"
|
||||||
|
}
|
||||||
|
)
|
@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.soundcloud.ad.fingerprints
|
package app.revanced.patches.soundcloud.shared.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
Loading…
Reference in New Issue
Block a user