fix(YouTube Music): Fix compatibility with latest versions (#2924)

This commit is contained in:
oSumAtrIX 2024-03-27 19:02:17 +01:00
parent 497c067e80
commit 8378c84816
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
22 changed files with 317 additions and 357 deletions

View File

@ -302,6 +302,12 @@ public final class app/revanced/patches/moneymanager/UnlockProPatch : app/revanc
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/music/ad/video/HideMusicVideoAds : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/music/ad/video/HideMusicVideoAds;
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/music/ad/video/MusicVideoAdsPatch : app/revanced/patcher/patch/BytecodePatch { public final class app/revanced/patches/music/ad/video/MusicVideoAdsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/music/ad/video/MusicVideoAdsPatch; public static final field INSTANCE Lapp/revanced/patches/music/ad/video/MusicVideoAdsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@ -314,6 +320,12 @@ public final class app/revanced/patches/music/audio/codecs/CodecsUnlockPatch : a
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/music/audio/exclusiveaudio/EnableExclusiveAudioPlayback : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/music/audio/exclusiveaudio/EnableExclusiveAudioPlayback;
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/music/audio/exclusiveaudio/ExclusiveAudioPatch : app/revanced/patcher/patch/BytecodePatch { public final class app/revanced/patches/music/audio/exclusiveaudio/ExclusiveAudioPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/music/audio/exclusiveaudio/ExclusiveAudioPatch; public static final field INSTANCE Lapp/revanced/patches/music/audio/exclusiveaudio/ExclusiveAudioPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@ -326,6 +338,12 @@ public final class app/revanced/patches/music/interaction/permanentrepeat/Perman
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/music/interaction/permanentshuffle/PermanentShufflePatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/music/interaction/permanentshuffle/PermanentShufflePatch;
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/music/interaction/permanentshuffle/PermanentShuffleTogglePatch : app/revanced/patcher/patch/BytecodePatch { public final class app/revanced/patches/music/interaction/permanentshuffle/PermanentShuffleTogglePatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/music/interaction/permanentshuffle/PermanentShuffleTogglePatch; public static final field INSTANCE Lapp/revanced/patches/music/interaction/permanentshuffle/PermanentShuffleTogglePatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@ -338,6 +356,12 @@ public final class app/revanced/patches/music/layout/compactheader/CompactHeader
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/music/layout/compactheader/HideCategoryBar : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/music/layout/compactheader/HideCategoryBar;
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/music/layout/minimizedplayback/MinimizedPlaybackPatch : app/revanced/patcher/patch/BytecodePatch { public final class app/revanced/patches/music/layout/minimizedplayback/MinimizedPlaybackPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/music/layout/minimizedplayback/MinimizedPlaybackPatch; public static final field INSTANCE Lapp/revanced/patches/music/layout/minimizedplayback/MinimizedPlaybackPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V

View File

@ -0,0 +1,37 @@
package app.revanced.patches.music.ad.video
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
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.proxy.mutableTypes.MutableMethod
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsParentFingerprint
import app.revanced.util.exception
@Patch(
name = "Hide music video ads",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
)
@Suppress("unused")
object HideMusicVideoAds : BytecodePatch(
setOf(ShowMusicVideoAdsParentFingerprint),
) {
override fun execute(context: BytecodeContext) {
ShowMusicVideoAdsParentFingerprint.result?.let {
val showMusicVideoAdsMethod = context
.toMethodWalker(it.mutableMethod)
.nextMethod(it.scanResult.patternScanResult!!.startIndex + 1, true).getMethod() as MutableMethod
showMusicVideoAdsMethod.addInstruction(0, "const/4 p1, 0x0")
} ?: throw ShowMusicVideoAdsParentFingerprint.exception
}
}
@Deprecated("This patch class has been renamed to HideMusicVideoAds.")
object MusicVideoAdsPatch : BytecodePatch(
dependencies = setOf(HideMusicVideoAds::class),
) {
override fun execute(context: BytecodeContext) {
}
}

View File

@ -1,32 +0,0 @@
package app.revanced.patches.music.ad.video
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsConstructorFingerprint
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsFingerprint
@Patch(
name = "Music video ads",
description = "Removes ads in the music player.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
)
@Suppress("unused")
object MusicVideoAdsPatch : BytecodePatch(
setOf(ShowMusicVideoAdsConstructorFingerprint)
) {
override fun execute(context: BytecodeContext) {
ShowMusicVideoAdsFingerprint.resolve(context, ShowMusicVideoAdsConstructorFingerprint.result!!.classDef)
val result = ShowMusicVideoAdsFingerprint.result!!
result.mutableMethod.addInstruction(
result.scanResult.patternScanResult!!.startIndex,
"""
const/4 p1, 0x0
"""
)
}
}

View File

@ -1,27 +0,0 @@
package app.revanced.patches.music.ad.video.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
internal object ShowMusicVideoAdsConstructorFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf(
Opcode.INVOKE_DIRECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.CONST_4,
Opcode.IPUT_BOOLEAN,
Opcode.RETURN_VOID
)
)

View File

@ -1,14 +0,0 @@
package app.revanced.patches.music.ad.video.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 ShowMusicVideoAdsFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), listOf(
Opcode.IPUT_BOOLEAN,
Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID
)
)

View File

@ -0,0 +1,13 @@
package app.revanced.patches.music.ad.video.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
internal object ShowMusicVideoAdsParentFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
),
strings = listOf("maybeRegenerateCpnAndStatsClient called unexpectedly, but no error."),
)

View File

@ -10,13 +10,12 @@ import app.revanced.patches.music.audio.codecs.fingerprints.CodecsLockFingerprin
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@Patch( @Patch(
name = "Codecs unlock",
description = "Adds more audio codec options. The new audio codecs usually result in better audio quality.", description = "Adds more audio codec options. The new audio codecs usually result in better audio quality.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")] compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
) )
@Suppress("unused") @Deprecated("This patch is no longer needed as the feature is now enabled by default.")
object CodecsUnlockPatch : BytecodePatch( object CodecsUnlockPatch : BytecodePatch(
setOf(CodecsLockFingerprint, AllCodecsReferenceFingerprint) setOf(CodecsLockFingerprint, AllCodecsReferenceFingerprint),
) { ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
val codecsLockResult = CodecsLockFingerprint.result!! val codecsLockResult = CodecsLockFingerprint.result!!
@ -25,13 +24,13 @@ object CodecsUnlockPatch : BytecodePatch(
val scanResultStartIndex = codecsLockResult.scanResult.patternScanResult!!.startIndex val scanResultStartIndex = codecsLockResult.scanResult.patternScanResult!!.startIndex
val instructionIndex = scanResultStartIndex + val instructionIndex = scanResultStartIndex +
if (implementation.instructions[scanResultStartIndex - 1].opcode == Opcode.CHECK_CAST) { if (implementation.instructions[scanResultStartIndex - 1].opcode == Opcode.CHECK_CAST) {
// for 5.16.xx and lower // for 5.16.xx and lower
-3 -3
} else { } else {
// since 5.17.xx // since 5.17.xx
-2 -2
} }
val allCodecsResult = AllCodecsReferenceFingerprint.result!! val allCodecsResult = AllCodecsReferenceFingerprint.result!!
val allCodecsMethod = val allCodecsMethod =
@ -41,7 +40,7 @@ object CodecsUnlockPatch : BytecodePatch(
implementation.replaceInstruction( implementation.replaceInstruction(
instructionIndex, instructionIndex,
"invoke-static {}, ${allCodecsMethod.definingClass}->${allCodecsMethod.name}()Ljava/util/Set;".toInstruction() "invoke-static {}, ${allCodecsMethod.definingClass}->${allCodecsMethod.name}()Ljava/util/Set;".toInstruction(),
) )
} }
} }

View File

@ -1,31 +1,36 @@
package app.revanced.patches.music.audio.exclusiveaudio package app.revanced.patches.music.audio.exclusiveaudio
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.audio.exclusiveaudio.fingerprints.AllowExclusiveAudioPlaybackFingerprint import app.revanced.patches.music.audio.exclusiveaudio.fingerprints.AllowExclusiveAudioPlaybackFingerprint
import app.revanced.util.exception
@Patch( @Patch(
name = "Exclusive audio playback", name = "Enable exclusive audio playback",
description = "Enables the option to play audio without video.", description = "Enables the option to play audio without video.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")] compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
) )
@Suppress("unused") @Suppress("unused")
object ExclusiveAudioPatch : BytecodePatch( object EnableExclusiveAudioPlayback : BytecodePatch(
setOf(AllowExclusiveAudioPlaybackFingerprint) setOf(AllowExclusiveAudioPlaybackFingerprint),
) { ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
AllowExclusiveAudioPlaybackFingerprint.result?.mutableMethod?.apply { AllowExclusiveAudioPlaybackFingerprint.result?.mutableMethod?.apply {
addInstructions( addInstructions(
0, 0,
""" """
const/4 v0, 0x1 const/4 v0, 0x1
return v0 return v0
""" """,
) )
} ?: throw AllowExclusiveAudioPlaybackFingerprint.exception } ?: throw AllowExclusiveAudioPlaybackFingerprint.exception
} }
} }
@Deprecated("This patch class has been renamed to EnableExclusiveAudioPlayback.")
object ExclusiveAudioPatch : BytecodePatch(emptySet()) {
override fun execute(context: BytecodeContext) = EnableExclusiveAudioPlayback.execute(context)
}

View File

@ -1,25 +1,32 @@
package app.revanced.patches.music.interaction.permanentshuffle package app.revanced.patches.music.interaction.permanentshuffle
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.interaction.permanentshuffle.fingerprints.DisableShuffleFingerprint import app.revanced.patches.music.interaction.permanentshuffle.fingerprints.DisableShuffleFingerprint
import app.revanced.util.exception
@Patch( @Patch(
name = "Permanent shuffle", name = "Permanent shuffle",
description = "Permanently remember your shuffle preference " + description = "Permanently remember your shuffle preference " +
"even if the playlist ends or another track is played.", "even if the playlist ends or another track is played.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")], compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
use = false use = false,
) )
@Suppress("unused") @Suppress("unused")
object PermanentShuffleTogglePatch : BytecodePatch(setOf(DisableShuffleFingerprint)) { object PermanentShufflePatch : BytecodePatch(setOf(DisableShuffleFingerprint)) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
DisableShuffleFingerprint.result?.mutableMethod?.addInstruction(0, "return-void") DisableShuffleFingerprint.result?.mutableMethod?.addInstruction(0, "return-void")
?: throw DisableShuffleFingerprint.exception ?: throw DisableShuffleFingerprint.exception
} }
} }
@Deprecated("This patch class has been renamed to PermanentShufflePatch.")
object PermanentShuffleTogglePatch : BytecodePatch(
dependencies = setOf(PermanentShufflePatch::class),
) {
override fun execute(context: BytecodeContext) {
}
}

View File

@ -1,34 +0,0 @@
package app.revanced.patches.music.layout.compactheader
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.layout.compactheader.fingerprints.CompactHeaderConstructorFingerprint
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction11x
@Patch(
name = "Compact header",
description = "Hides the music category bar at the top of the homepage.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
use = false
)
@Suppress("unused")
object CompactHeaderPatch : BytecodePatch(
setOf(CompactHeaderConstructorFingerprint)
) {
override fun execute(context: BytecodeContext) {
val result = CompactHeaderConstructorFingerprint.result!!
val method = result.mutableMethod
val insertIndex = result.scanResult.patternScanResult!!.endIndex
val register = (method.implementation!!.instructions[insertIndex - 1] as BuilderInstruction11x).registerA
method.addInstructions(
insertIndex, """
const/16 v2, 0x8
invoke-virtual {v${register}, v2}, Landroid/view/View;->setVisibility(I)V
"""
)
}
}

View File

@ -0,0 +1,47 @@
package app.revanced.patches.music.layout.compactheader
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.layout.compactheader.fingerprints.ConstructCategoryBarFingerprint
import app.revanced.util.exception
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch(
name = "Hide category bar",
description = "Hides the category bar at the top of the homepage.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
use = false,
)
@Suppress("unused")
object HideCategoryBar : BytecodePatch(
setOf(ConstructCategoryBarFingerprint),
) {
override fun execute(context: BytecodeContext) {
ConstructCategoryBarFingerprint.result?.let {
it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.startIndex
val register = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
addInstructions(
insertIndex,
"""
const/16 v2, 0x8
invoke-virtual {v$register, v2}, Landroid/view/View;->setVisibility(I)V
""",
)
}
} ?: throw ConstructCategoryBarFingerprint.exception
}
}
@Deprecated("This patch class has been renamed to HideCategoryBar.")
object CompactHeaderPatch : BytecodePatch(
dependencies = setOf(HideCategoryBar::class),
) {
override fun execute(context: BytecodeContext) {
}
}

View File

@ -5,19 +5,19 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal object CompactHeaderConstructorFingerprint : MethodFingerprint( internal object ConstructCategoryBarFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L"), listOf( "V",
Opcode.INVOKE_DIRECT, AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
Opcode.IPUT_OBJECT, listOf("Landroid/content/Context;", "L", "L", "L"),
Opcode.IPUT_OBJECT, listOf(
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT,
Opcode.CONST, Opcode.CONST,
Opcode.CONST_4, Opcode.INVOKE_VIRTUAL,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST Opcode.IPUT_OBJECT,
) Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
),
) )

View File

@ -1,26 +1,39 @@
package app.revanced.patches.music.layout.minimizedplayback package app.revanced.patches.music.layout.minimizedplayback
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint import app.revanced.patches.music.layout.minimizedplayback.fingerprints.BackgroundPlaybackDisableFingerprint
import app.revanced.patches.music.layout.minimizedplayback.fingerprints.KidsMinimizedPlaybackPolicyControllerFingerprint
import app.revanced.util.exception
@Patch( @Patch(
name = "Minimized playback music", name = "Minimized playback",
description = "Enables minimized playback on Kids music.", description = "Unlocks options for picture-in-picture and background playback.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")] compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
) )
@Suppress("unused") @Suppress("unused")
object MinimizedPlaybackPatch : BytecodePatch(setOf(MinimizedPlaybackManagerFingerprint)) { object MinimizedPlaybackPatch : BytecodePatch(
override fun execute(context: BytecodeContext) = setOf(
MinimizedPlaybackManagerFingerprint.result?.mutableMethod?.addInstruction( KidsMinimizedPlaybackPolicyControllerFingerprint,
BackgroundPlaybackDisableFingerprint,
),
) {
override fun execute(context: BytecodeContext) {
KidsMinimizedPlaybackPolicyControllerFingerprint.result?.mutableMethod?.addInstruction(
0,
"return-void",
) ?: throw KidsMinimizedPlaybackPolicyControllerFingerprint.exception
BackgroundPlaybackDisableFingerprint.result?.mutableMethod?.addInstructions(
0, 0,
""" """
return-void const/4 v0, 0x1
""" return v0
) ?: throw MinimizedPlaybackManagerFingerprint.exception """,
) ?: throw BackgroundPlaybackDisableFingerprint.exception
}
} }

View File

@ -0,0 +1,23 @@
package app.revanced.patches.music.layout.minimizedplayback.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 BackgroundPlaybackDisableFingerprint : MethodFingerprint(
"Z",
AccessFlags.PUBLIC or AccessFlags.STATIC,
listOf("L"),
listOf(
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.IGET,
Opcode.AND_INT_LIT16,
Opcode.IF_EQZ,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET,
),
)

View File

@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal object MinimizedPlaybackManagerFingerprint : MethodFingerprint( internal object KidsMinimizedPlaybackPolicyControllerFingerprint : MethodFingerprint(
"V", "V",
AccessFlags.PUBLIC or AccessFlags.FINAL, AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("I", "L", "Z"), listOf("I", "L", "Z"),
@ -22,5 +22,5 @@ internal object MinimizedPlaybackManagerFingerprint : MethodFingerprint(
Opcode.CONST_4, Opcode.CONST_4,
Opcode.IF_NE, Opcode.IF_NE,
Opcode.IPUT_BOOLEAN, Opcode.IPUT_BOOLEAN,
) ),
) )

View File

@ -2,41 +2,44 @@ package app.revanced.patches.music.layout.premium
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumFingerprint import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumFingerprint
import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumParentFingerprint import app.revanced.util.exception
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@Patch( @Patch(
name = "Hide get premium", name = "Hide 'Get Music Premium' label",
description = "Removes all \"Get Premium\" evidences from the avatar menu.", description = "Hides the red \"Get Music Premium\" label from the account menu.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")] compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
) )
@Suppress("unused") @Suppress("unused")
object HideGetPremiumPatch : BytecodePatch(setOf(HideGetPremiumParentFingerprint)) { object HideGetPremiumPatch : BytecodePatch(
setOf(HideGetPremiumFingerprint),
) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
val parentResult = HideGetPremiumParentFingerprint.result!! HideGetPremiumFingerprint.result?.let {
HideGetPremiumFingerprint.resolve(context, parentResult.classDef) it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.endIndex
val startIndex = parentResult.scanResult.patternScanResult!!.startIndex val setVisibilityInstruction = getInstruction<FiveRegisterInstruction>(insertIndex)
val getPremiumViewRegister = setVisibilityInstruction.registerC
val visibilityRegister = setVisibilityInstruction.registerD
val parentMethod = parentResult.mutableMethod replaceInstruction(
parentMethod.replaceInstruction( insertIndex,
startIndex, "const/16 v$visibilityRegister, 0x8",
""" )
const/4 v1, 0x0
"""
)
val result = HideGetPremiumFingerprint.result!! addInstruction(
val method = result.mutableMethod insertIndex + 1,
method.addInstruction( "invoke-virtual {v$getPremiumViewRegister, v$visibilityRegister}, " +
startIndex, "Landroid/view/View;->setVisibility(I)V",
""" )
const/16 v0, 0x8 }
""" } ?: throw HideGetPremiumFingerprint.exception
)
} }
} }

View File

@ -6,11 +6,13 @@ import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal object HideGetPremiumFingerprint : MethodFingerprint( internal object HideGetPremiumFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( "V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf(),
listOf(
Opcode.IF_NEZ, Opcode.IF_NEZ,
Opcode.CONST_16, Opcode.CONST_16,
Opcode.GOTO, Opcode.INVOKE_VIRTUAL,
Opcode.NOP, ),
Opcode.INVOKE_VIRTUAL listOf("FEmusic_history", "FEmusic_offline"),
)
) )

View File

@ -1,19 +0,0 @@
package app.revanced.patches.music.layout.premium.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 HideGetPremiumParentFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
Opcode.IGET_BOOLEAN,
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC
),
listOf("FEmusic_history"),
)

View File

@ -1,71 +1,84 @@
package app.revanced.patches.music.layout.upgradebutton package app.revanced.patches.music.layout.upgradebutton
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
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.extensions.newLabel
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage 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.toInstructions import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.music.layout.upgradebutton.fingerprints.PivotBarConstructorFingerprint import app.revanced.patches.music.layout.upgradebutton.fingerprints.PivotBarConstructorFingerprint
import app.revanced.util.exception
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22t import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22t
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@Patch( @Patch(
name = "Remove upgrade button", name = "Remove upgrade button",
description = "Removes the upgrade tab from the pivot bar.", description = "Removes the upgrade tab from the pivot bar.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")] compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
) )
@Suppress("unused") @Suppress("unused")
object RemoveUpgradeButtonPatch : BytecodePatch( object RemoveUpgradeButtonPatch : BytecodePatch(
setOf(PivotBarConstructorFingerprint) setOf(PivotBarConstructorFingerprint),
) { ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
val result = PivotBarConstructorFingerprint.result!! PivotBarConstructorFingerprint.result?.let {
val implementation = result.mutableMethod.implementation!! it.mutableMethod.apply {
val pivotBarElementFieldReference = getInstruction(it.scanResult.patternScanResult!!.endIndex - 1)
.getReference<FieldReference>()
val pivotBarElementFieldRef = val register = (getInstructions().first() as Instruction35c).registerC
(implementation.instructions[result.scanResult.patternScanResult!!.endIndex - 1] as Instruction22c).reference
val register = (implementation.instructions.first() as Instruction35c).registerC // First compile all the needed instructions.
// first compile all the needed instructions val instructionList = """
val instructionList = """ invoke-interface { v0 }, Ljava/util/List;->size()I
invoke-interface { v0 }, Ljava/util/List;->size()I move-result v1
move-result v1 const/4 v2, 0x4
const/4 v2, 0x4 invoke-interface {v0, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object;
invoke-interface {v0, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object; iput-object v0, v$register, $pivotBarElementFieldReference
iput-object v0, v$register, $pivotBarElementFieldRef """.toInstructions().toMutableList()
""".toInstructions().toMutableList()
val endIndex = it.scanResult.patternScanResult!!.endIndex
val endIndex = result.scanResult.patternScanResult!!.endIndex // Replace the instruction to retain the label at given index.
replaceInstruction(
endIndex - 1,
instructionList[0], // invoke-interface.
)
// Do not forget to remove this instruction since we added it already.
instructionList.removeFirst()
// replace the instruction to retain the label at given index val exitInstruction = instructionList.last() // iput-object
implementation.replaceInstruction( addInstruction(
endIndex - 1, instructionList[0] // invoke-interface endIndex,
) exitInstruction,
// do not forget to remove this instruction since we added it already )
instructionList.removeFirst() // Do not forget to remove this instruction since we added it already.
instructionList.removeLast()
val exitInstruction = instructionList.last() // iput-object // Add the necessary if statement to remove the upgrade tab button in case it exists.
implementation.addInstruction( instructionList.add(
endIndex, exitInstruction 2, // if-le.
) BuilderInstruction22t(
// do not forget to remove this instruction since we added it already Opcode.IF_LE,
instructionList.removeLast() 1,
2,
newLabel(endIndex),
),
)
// add the necessary if statement to remove the upgrade tab button in case it exists addInstructions(
instructionList.add( endIndex,
2, // if-le instructionList,
BuilderInstruction22t( )
Opcode.IF_LE, 1, 2, implementation.newLabelForIndex(endIndex) }
) } ?: throw PivotBarConstructorFingerprint.exception
)
implementation.addInstructions(
endIndex, instructionList
)
} }
} }

View File

@ -1,62 +1,19 @@
package app.revanced.patches.music.layout.upgradebutton.fingerprints package app.revanced.patches.music.layout.upgradebutton.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
internal object PivotBarConstructorFingerprint : MethodFingerprint( internal object PivotBarConstructorFingerprint : MethodFingerprint(
"V", "V",
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
listOf("L", "Z"), listOf("L", "Z"),
listOf( listOf(
Opcode.INVOKE_DIRECT,
Opcode.CONST_4,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_BOOLEAN,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.GOTO,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.IGET,
Opcode.CONST,
Opcode.IF_NE,
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST,
Opcode.GOTO,
Opcode.SGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.IGET,
Opcode.CONST,
Opcode.IF_NE,
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST, Opcode.CHECK_CAST,
Opcode.INVOKE_INTERFACE, Opcode.INVOKE_INTERFACE,
Opcode.GOTO, Opcode.GOTO,
Opcode.NOP,
Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT,
Opcode.RETURN_VOID Opcode.RETURN_VOID,
) ),
) )

View File

@ -1,26 +1,12 @@
package app.revanced.patches.music.premium.backgroundplay package app.revanced.patches.music.premium.backgroundplay
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patches.music.layout.minimizedplayback.MinimizedPlaybackPatch
import app.revanced.patcher.patch.annotation.Patch @Deprecated("This patch has been merged into MinimizedPlaybackPatch.")
import app.revanced.patches.music.premium.backgroundplay.fingerprints.BackgroundPlaybackDisableFingerprint object BackgroundPlayPatch : BytecodePatch(
dependencies = setOf(MinimizedPlaybackPatch::class),
) {
@Patch( override fun execute(context: BytecodeContext) {
name = "Background play", }
description = "Enables playing music in the background.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
)
@Suppress("unused")
object BackgroundPlayPatch : BytecodePatch(setOf(BackgroundPlaybackDisableFingerprint)) {
override fun execute(context: BytecodeContext) =
BackgroundPlaybackDisableFingerprint.result?.mutableMethod?.addInstructions(
0, """
const/4 v0, 0x1
return v0
"""
) ?: throw BackgroundPlaybackDisableFingerprint.exception
} }

View File

@ -1,43 +0,0 @@
package app.revanced.patches.music.premium.backgroundplay.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
internal object BackgroundPlaybackDisableFingerprint : MethodFingerprint(
"Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.IGET,
Opcode.AND_INT_LIT16,
Opcode.IF_EQZ,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET,
Opcode.CONST,
Opcode.IF_NE,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET,
Opcode.IF_NE,
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST,
Opcode.GOTO,
Opcode.SGET_OBJECT,
Opcode.GOTO,
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.IGET_BOOLEAN,
Opcode.IF_EQZ,
Opcode.CONST_4,
Opcode.RETURN,
Opcode.RETURN,
Opcode.RETURN
)
)