mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2024-11-10 01:01:56 +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
6 changed files with 132 additions and 2 deletions
|
@ -1050,6 +1050,12 @@ public final class app/revanced/patches/soundcloud/analytics/DisableTelemetryPat
|
|||
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 static final field INSTANCE Lapp/revanced/patches/spotify/layout/theme/CustomThemePatch;
|
||||
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.util.smali.ExternalLabel
|
||||
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.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.fingerprint.MethodFingerprint
|
Loading…
Reference in a new issue