improve music patch

This commit is contained in:
inotia00
2023-01-05 12:05:03 +09:00
parent 73449598c2
commit 33dd92ec93
92 changed files with 872 additions and 1412 deletions

View File

@ -13,6 +13,7 @@ import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.patches.videoads.GeneralVideoAdsPatch
import app.revanced.shared.util.integrations.Constants.MUSIC_SETTINGS_PATH
@Patch
@DependsOn(
@ -22,13 +23,13 @@ import app.revanced.shared.patches.videoads.GeneralVideoAdsPatch
MusicSettingsPatch::class
]
)
@Name("music-video-ads")
@Name("hide-music-ads")
@Description("Removes ads in the music player.")
@YouTubeMusicCompatibility
@Version("0.0.1")
class MusicVideoAdsPatch : BytecodePatch() {
override fun execute(context: BytecodeContext): PatchResult {
val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/settings/MusicSettings;->getShowAds()Z"
val INTEGRATIONS_CLASS_DESCRIPTOR = "$MUSIC_SETTINGS_PATH->hideMusicAds()Z"
GeneralVideoAdsPatch.injectLegacyAds(INTEGRATIONS_CLASS_DESCRIPTOR)

View File

@ -8,7 +8,10 @@ import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
object AllCodecsReferenceFingerprint : MethodFingerprint(
"J", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
returnType = "J",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L"),
opcodes = listOf(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
@ -47,5 +50,6 @@ object AllCodecsReferenceFingerprint : MethodFingerprint(
Opcode.INVOKE_SUPER,
Opcode.MOVE_RESULT_WIDE,
Opcode.RETURN_WIDE
), listOf("itag")
),
strings = listOf("itag")
)

View File

@ -1,20 +1,16 @@
package app.revanced.patches.music.audio.codecs.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("codec-lock-fingerprint")
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@YouTubeMusicCompatibility
@Version("0.0.1")
object CodecsLockFingerprint : MethodFingerprint(
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf(
returnType = "L",
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
opcodes = listOf(
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,

View File

@ -18,12 +18,13 @@ import app.revanced.patches.music.audio.codecs.fingerprints.CodecsLockFingerprin
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.util.integrations.Constants.MUSIC_SETTINGS_PATH
import org.jf.dexlib2.Opcode
@Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@Name("codecs-unlock")
@Description("Adds more audio codec options. The new audio codecs usually result in better audio quality.")
@Name("enable-opus-codec")
@Description("Enable opus codec when playing audio.")
@YouTubeMusicCompatibility
@Version("0.0.1")
class CodecsUnlockPatch : BytecodePatch(
@ -55,7 +56,7 @@ class CodecsUnlockPatch : BytecodePatch(
codecsLockMethod.addInstructions(
instructionIndex + 2, """
invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getCodecsUnlock()Z
invoke-static {}, $MUSIC_SETTINGS_PATH->enableOpusCodec()Z
move-result v7
if-eqz v7, :mp4a
invoke-static {}, ${allCodecsMethod.definingClass}->${allCodecsMethod.name}()Ljava/util/Set;

View File

@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object AudioOnlyEnablerFingerprint: MethodFingerprint(
"Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
returnType = "Z",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,

View File

@ -1,84 +0,0 @@
package app.revanced.patches.music.layout.blacknavbar.bytecode.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.extensions.findMutableMethodOf
import app.revanced.shared.patches.mapping.ResourceMappingPatch
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.Opcode
@Patch
@DependsOn(
[
MusicIntegrationsPatch::class,
MusicSettingsPatch::class,
ResourceMappingPatch::class
]
)
@Name("black-navbar")
@Description("Sets the navigation bar color to black.")
@YouTubeMusicCompatibility
@Version("0.0.1")
class BlackNavbarPatch : BytecodePatch() {
// list of resource names to get the id of
private val resourceIds = arrayOf(
"ytm_color_grey_12"
).map { name ->
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
}
override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef ->
classDef.methods.forEach { method ->
with(method.implementation) {
this?.instructions?.forEachIndexed { index, instruction ->
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> { // blacknavbar
val insertIndex = index - 1
val insertIndex2 = index + 2
val invokeInstruction = instructions.elementAt(insertIndex)
val invokeInstruction2 = instructions.elementAt(insertIndex2)
if (invokeInstruction.opcode != Opcode.MOVE_RESULT_OBJECT) return@forEachIndexed
val register1 = (instructions.elementAt(index) as Instruction31i).registerA
val register2 = (invokeInstruction2 as Instruction11x).registerA
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
mutableMethod.addInstructions(
index + 3, """
invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getBlackNavbar()Z
move-result v$register1
if-eqz v$register1, :default
const/high16 v$register2, -0x1000000
""", listOf(ExternalLabel("default", mutableMethod.instruction(index + 3)))
)
}
}
}
else -> return@forEachIndexed
}
}
}
}
}
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,26 @@
package app.revanced.patches.music.layout.blacknavbar.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourcdIdPatch
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object TabLayoutFingerprint : MethodFingerprint(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
opcodes = listOf(
Opcode.CONST,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT
),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction ->
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.colorGreyLabelId
} == true
}
)

View File

@ -0,0 +1,63 @@
package app.revanced.patches.music.layout.blacknavbar.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.layout.blacknavbar.fingerprints.TabLayoutFingerprint
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.resourceid.patch.SharedResourcdIdPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.util.integrations.Constants.MUSIC_SETTINGS_PATH
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
@Patch
@Name("enable-black-navbar")
@Description("Sets the navigation bar color to black.")
@DependsOn(
[
MusicIntegrationsPatch::class,
MusicSettingsPatch::class,
SharedResourcdIdPatch::class
]
)
@YouTubeMusicCompatibility
@Version("0.0.1")
class BlackNavbarPatch : BytecodePatch(
listOf(
TabLayoutFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val result = TabLayoutFingerprint.result!!
val method = result.mutableMethod
val startIndex = result.scanResult.patternScanResult!!.startIndex
val endIndex = result.scanResult.patternScanResult!!.endIndex
val insertIndex = endIndex + 1
val dummyRegister = (method.instruction(startIndex) as Instruction31i).registerA
val targetRegister = (method.instruction(endIndex) as Instruction11x).registerA
method.addInstructions(
insertIndex, """
invoke-static {}, $MUSIC_SETTINGS_PATH->enableBlackNavbar()Z
move-result v$dummyRegister
if-eqz v$dummyRegister, :default
const/high16 v$targetRegister, -0x1000000
""", listOf(ExternalLabel("default", method.instruction(insertIndex)))
)
return PatchResultSuccess()
}
}

View File

@ -1,15 +1,11 @@
package app.revanced.patches.music.layout.castbutton.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
@Name("hide-castbutton-signature")
@YouTubeMusicCompatibility
@Version("0.0.1")
object HideCastButtonFingerprint : MethodFingerprint (
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("I"), null ,null, null
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("I")
)

View File

@ -1,16 +1,11 @@
package app.revanced.patches.music.layout.castbutton.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
@Name("hide-castbutton-parent-signature")
@YouTubeMusicCompatibility
@Version("0.0.1")
object HideCastButtonParentFingerprint : MethodFingerprint (
"Z", AccessFlags.PRIVATE or AccessFlags.FINAL,
returnType = "Z",
access = AccessFlags.PRIVATE or AccessFlags.FINAL,
strings = listOf("MediaRouteButton")
)

View File

@ -17,6 +17,7 @@ import app.revanced.patches.music.layout.castbutton.fingerprints.HideCastButtonP
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.util.integrations.Constants.MUSIC_SETTINGS_PATH
@Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@ -36,7 +37,7 @@ class HideWatermarkPatch : BytecodePatch(
result.mutableMethod.addInstructions(
0, """
invoke-static {p1}, Lapp/revanced/integrations/settings/MusicSettings;->getCastButtonOverrideV2(I)I
invoke-static {p1}, $MUSIC_SETTINGS_PATH->hideCastButton(I)I
move-result p1
"""
)

View File

@ -1,18 +1,15 @@
package app.revanced.patches.music.layout.compactheader.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("compact-header-constructor-fingerprint")
@YouTubeMusicCompatibility
@Version("0.0.1")
object CompactHeaderConstructorFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L"), listOf(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L", "L", "L", "L", "L"),
opcodes = listOf(
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,

View File

@ -14,11 +14,12 @@ import app.revanced.patches.music.layout.compactheader.fingerprints.CompactHeade
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.util.integrations.Constants.MUSIC_SETTINGS_PATH
import org.jf.dexlib2.builder.instruction.BuilderInstruction11x
@Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@Name("compact-header")
@Name("hide-compact-header")
@Description("Hides the music category bar at the top of the homepage.")
@YouTubeMusicCompatibility
@Version("0.0.1")
@ -35,7 +36,7 @@ class CompactHeaderPatch : BytecodePatch(
val register = (method.implementation!!.instructions[insertIndex - 1] as BuilderInstruction11x).registerA
method.addInstructions(
insertIndex, """
invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getCompactHeader()I
invoke-static {}, $MUSIC_SETTINGS_PATH->hideCompactHeader()I
move-result v2
invoke-virtual {v${register}, v2}, Landroid/view/View;->setVisibility(I)V
"""

View File

@ -1,21 +1,15 @@
package app.revanced.patches.music.layout.minimizedplayback.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("minimized-playback-manager-fingerprint")
@YouTubeMusicCompatibility
@Version("0.0.1")
object MinimizedPlaybackManagerFingerprint : MethodFingerprint(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("I", "L", "Z"),
listOf(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("I", "L", "Z"),
opcodes = listOf(
Opcode.IGET,
Opcode.IF_NE,
Opcode.IGET_OBJECT,
@ -27,6 +21,6 @@ object MinimizedPlaybackManagerFingerprint : MethodFingerprint(
Opcode.SGET_OBJECT,
Opcode.CONST_4,
Opcode.IF_NE,
Opcode.IPUT_BOOLEAN,
Opcode.IPUT_BOOLEAN
)
)

View File

@ -1,18 +1,15 @@
package app.revanced.patches.music.layout.minimizedplayer.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("minimized-player-fingerprint")
@YouTubeMusicCompatibility
@Version("0.0.1")
object MinimizedPlayerFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L"), listOf(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "L"),
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.SGET_OBJECT,

View File

@ -15,12 +15,13 @@ import app.revanced.patches.music.layout.minimizedplayer.fingerprints.MinimizedP
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.util.integrations.Constants.MUSIC_SETTINGS_PATH
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@Name("minimized-player")
@Name("enable-force-minimized-player")
@Description("Permanently keep player minimized even if another track is played.")
@YouTubeMusicCompatibility
@Version("0.0.1")
@ -39,7 +40,7 @@ class MinimizedPlayerPatch : BytecodePatch(
method.addInstructions(
index, """
invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getEnforceMinimizedPlayer()Z
invoke-static {}, $MUSIC_SETTINGS_PATH->enableForceMinimizedPlayer()Z
move-result v$register
if-nez v$register, :enforce
""", listOf(ExternalLabel("enforce", jumpInstruction))

View File

@ -1,18 +1,15 @@
package app.revanced.patches.music.layout.miniplayercolor.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("miniplayer-color-fingerprint")
@YouTubeMusicCompatibility
@Version("0.0.1")
object MiniplayerColorFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "J"), listOf(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "J"),
opcodes = listOf(
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.RETURN_VOID

View File

@ -14,10 +14,11 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.layout.miniplayercolor.fingerprints.MiniplayerColorFingerprint
import app.revanced.patches.music.layout.miniplayercolor.fingerprints.MiniplayerColorParentFingerprint
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.fingerprints.MiniplayerColorParentFingerprint
import app.revanced.shared.util.integrations.Constants.MUSIC_SETTINGS_PATH
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference
@ -25,7 +26,7 @@ import org.jf.dexlib2.iface.reference.MethodReference
@Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@Name("miniplayer-color")
@Name("enable-color-match-player")
@Description("Matches the fullscreen player color with the minimized one.")
@YouTubeMusicCompatibility
@Version("0.0.1")
@ -72,7 +73,7 @@ class MiniplayerColorPatch : BytecodePatch(
miniplayerColorMethod.addInstructions(
insertIndex, """
invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getMiniPlayerColor()Z
invoke-static {}, $MUSIC_SETTINGS_PATH->enableColorMatchPlayer()Z
move-result v2
if-eqz v2, :off
iget v0, p0, ${miniplayerColorResult.classDef.type}->${Reference_A_1.name}:${Reference_A_1.type}

View File

@ -1,18 +1,15 @@
package app.revanced.patches.music.layout.premium.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("hide-get-premium-fingerprint")
@YouTubeMusicCompatibility
@Version("0.0.1")
object HideGetPremiumFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
opcodes = listOf(
Opcode.IF_NEZ,
Opcode.CONST_16,
Opcode.GOTO,

View File

@ -1,18 +1,15 @@
package app.revanced.patches.music.layout.premium.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("hide-get-premium-parent-fingerprint")
@YouTubeMusicCompatibility
@Version("0.0.1")
object HideGetPremiumParentFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
opcodes = listOf(
Opcode.IGET_BOOLEAN,
Opcode.CONST_4,
Opcode.IF_EQZ,

View File

@ -1,74 +0,0 @@
package app.revanced.patches.music.layout.tabletmode.bytecode.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.extensions.findMutableMethodOf
import app.revanced.shared.patches.mapping.ResourceMappingPatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
@Patch
@DependsOn(
[
MusicIntegrationsPatch::class,
MusicSettingsPatch::class,
ResourceMappingPatch::class
]
)
@Name("tablet-mode")
@Description("Unlocks landscape mode.")
@YouTubeMusicCompatibility
@Version("0.0.1")
class TabletModePatch : BytecodePatch() {
// list of resource names to get the id of
private val resourceIds = arrayOf(
"is_tablet"
).map { name ->
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
}
override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef ->
classDef.methods.forEach { method ->
with(method.implementation) {
this?.instructions?.forEachIndexed { index, instruction ->
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> { // tablet
val insertIndex = index - 2
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
mutableMethod.addInstructions(
index + 3, """
invoke-static {p0}, Lapp/revanced/integrations/settings/MusicSettings;->getTabletMode(Z)Z
move-result p0
"""
)
}
}
}
else -> return@forEachIndexed
}
}
}
}
}
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,26 @@
package app.revanced.patches.music.layout.tabletmode.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.resourceid.patch.SharedResourcdIdPatch
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object TabletLayoutFingerprint : MethodFingerprint(
returnType = "Z",
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L"),
opcodes = listOf(
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT
),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction ->
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.isTabletLabelId
} == true
}
)

View File

@ -0,0 +1,54 @@
package app.revanced.patches.music.layout.tabletmode.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.music.layout.tabletmode.fingerprints.TabletLayoutFingerprint
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.resourceid.patch.SharedResourcdIdPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.util.integrations.Constants.MUSIC_SETTINGS_PATH
@Patch
@Name("enable-tablet-mode")
@Description("Enable landscape mode on phone.")
@DependsOn(
[
MusicIntegrationsPatch::class,
MusicSettingsPatch::class,
SharedResourcdIdPatch::class
]
)
@YouTubeMusicCompatibility
@Version("0.0.1")
class TabletModePatch : BytecodePatch(
listOf(
TabletLayoutFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val result = TabletLayoutFingerprint.result!!
val method = result.mutableMethod
val endIndex = result.scanResult.patternScanResult!!.endIndex
val insertIndex = endIndex + 1
method.addInstructions(
insertIndex, """
invoke-static {p0}, $MUSIC_SETTINGS_PATH->enableTabletMode(Z)Z
move-result p0
"""
)
return PatchResultSuccess()
}
}

View File

@ -1,20 +1,17 @@
package app.revanced.patches.music.layout.tastebuilder.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("taste-builder-constructor-fingerprint")
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@YouTubeMusicCompatibility
@Version("0.0.1")
object TasteBuilderConstructorFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L", "L", "L"),
opcodes = listOf(
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_VIRTUAL,
Opcode.NEW_INSTANCE,

View File

@ -14,7 +14,7 @@ import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
@Patch
@Name("tasteBuilder-remover")
@Name("hide-taste-builder")
@Description("Removes the \"Tell us which artists you like\" card from the home screen.")
@YouTubeMusicCompatibility
@Version("0.0.1")

View File

@ -1,23 +1,17 @@
package app.revanced.patches.music.layout.upgradebutton.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("pivot-bar-constructor-fingerprint")
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@YouTubeMusicCompatibility
@Version("0.0.1")
object PivotBarConstructorFingerprint : MethodFingerprint(
"V",
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
listOf("L", "Z"),
listOf(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L", "Z"),
opcodes = listOf(
Opcode.INVOKE_DIRECT,
Opcode.CONST_4,
Opcode.IPUT_OBJECT,

View File

@ -17,9 +17,8 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction22c
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
import org.jf.dexlib2.Opcode
@Patch
@Name("upgrade-button-remover")
@Name("hide-upgrade-button")
@Description("Removes the upgrade tab from the pivot bar.")
@YouTubeMusicCompatibility
@Version("0.0.1")

View File

@ -5,6 +5,10 @@ import org.jf.dexlib2.Opcode
object UserAgentHeaderBuilderFingerprint : MethodFingerprint(
parameters = listOf("L"),
opcodes = listOf(Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_VIRTUAL, Opcode.CONST_16),
opcodes = listOf(
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.CONST_16
),
strings = listOf("(Linux; U; Android ")
)

View File

@ -4,10 +4,11 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patches.music.misc.integrations.fingerprints.InitFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.patches.integrations.AbstractIntegrationsPatch
import app.revanced.shared.util.integrations.Constants.MUSIC_SETTINGS_PATH
@Name("music-integrations")
@YouTubeMusicCompatibility
class MusicIntegrationsPatch : AbstractIntegrationsPatch(
"Lapp/revanced/integrations/settings/MusicSettings;",
"$MUSIC_SETTINGS_PATH",
listOf(InitFingerprint),
)

View File

@ -0,0 +1,36 @@
package app.revanced.patches.music.misc.resourceid.patch
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.patches.mapping.ResourceMappingPatch
@Name("music-resource-id")
@DependsOn([ResourceMappingPatch::class])
@YouTubeMusicCompatibility
@Version("0.0.1")
class SharedResourcdIdPatch : ResourcePatch {
internal companion object {
var colorGreyLabelId: Long = -1
var disabledIconLabelId: Long = -1
var isTabletLabelId: Long = -1
}
override fun execute(context: ResourceContext): PatchResult {
fun findSharedResourceId(type: String, name: String) = ResourceMappingPatch
.resourceMappings
.single { it.type == type && it.name == name }.id
colorGreyLabelId = findSharedResourceId("color", "ytm_color_grey_12")
disabledIconLabelId = findSharedResourceId("dimen", "disabled_icon_alpha")
isTabletLabelId = findSharedResourceId("bool", "is_tablet")
return PatchResultSuccess()
}
}

View File

@ -4,16 +4,15 @@ import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import app.revanced.shared.util.resources.ResourceHelper
@Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@ -24,63 +23,28 @@ import java.nio.file.StandardCopyOption
class MusicTranslationsPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
val revanced_translations = "translate" to arrayOf(
"ar-v21",
"az-rAZ-v21",
"bg-rBG-v21",
"bn-rIN-v21",
"bn-v21",
"cs-rCZ-v21",
"de-rDE-v21",
"el-rGR-v21",
"es-rES-v21",
"fi-rFI-v21",
"fr-rFR-v21",
"hi-rIN-v21",
"hu-rHU-v21",
"id-rID-v21",
"in-v21",
"it-rIT-v21",
"ja-rJP-v21",
"kn-rIN-v21",
"ko-rKR-v21",
"ml-rIN-v21",
"nl-rNL-v21",
"pa-rIN-v21",
"pl-rPL-v21",
"pt-rBR-v21",
"pt-rPT-v21",
"ro-rRO-v21",
"ru-rRU-v21",
"sk-rSK-v21",
"sv-rFI-v21",
"sv-rSE-v21",
"ta-rIN-v21",
"th-v21",
"tr-rTR-v21",
"uk-rUA-v21",
"vi-rVN-v21",
"zh-rCN-v21",
"zh-rTW-v21"
)
val TranslationsResources = arrayOf(revanced_translations)
val classLoader = this.javaClass.classLoader
TranslationsResources.forEach { (path, languageNames) ->
languageNames.forEach { name ->
val resDirectory = context["res"].resolve("values-$name")
val relativePath = "values-$name/strings.xml"
Files.createDirectory(resDirectory.toPath())
Files.copy(
classLoader.getResourceAsStream("music/$path/$relativePath")!!,
context["res"].resolve(relativePath).toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
ResourceHelper.addTranslations(context, "music", LANGUAGE_LIST)
return PatchResultSuccess()
}
private companion object {
val LANGUAGE_LIST = arrayOf(
"be-rBY",
"bn",
"de-rDE",
"es-rES",
"fr-rFR",
"hi-rIN",
"id-rID",
"in",
"it-rIT",
"pt-rBR",
"ru-rRU",
"tr-rTR",
"uk-rUA",
"zh-rCN",
"zh-rTW"
)
}
}

View File

@ -8,7 +8,10 @@ import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
object BackgroundPlaybackDisableFingerprint : MethodFingerprint(
"Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(
returnType = "Z",
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L"),
opcodes = listOf(
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.IGET,

View File

@ -4,16 +4,14 @@ import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.util.resources.ResourceHelper
import java.nio.file.Files
import java.nio.file.StandardCopyOption
@Patch
@Name("translations")
@ -24,18 +22,7 @@ import java.nio.file.StandardCopyOption
class TranslationsPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
LANGUAGE_LIST.forEach { language ->
val directory = "values-" + language + "-v21"
val relativePath = "$language/strings.xml"
context["res/$directory"].mkdir()
Files.copy(
this.javaClass.classLoader.getResourceAsStream("youtube/translations/$relativePath")!!,
context["res"].resolve("$directory/strings.xml").toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
ResourceHelper.addTranslations(context, "youtube", LANGUAGE_LIST)
ResourceHelper.patchSuccess(
context,

View File

@ -1,21 +1,14 @@
package app.revanced.patches.music.layout.miniplayercolor.fingerprints
package app.revanced.shared.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("miniplayer-color-hook-fingerprint")
@YouTubeMusicCompatibility
@Version("0.0.1")
object MiniplayerColorParentFingerprint : MethodFingerprint(
"V",
AccessFlags.PRIVATE or AccessFlags.FINAL,
null,
listOf(
returnType = "V",
access = AccessFlags.PRIVATE or AccessFlags.FINAL,
opcodes = listOf(
Opcode.IGET,
Opcode.IGET,
Opcode.CONST_WIDE_16,

View File

@ -17,4 +17,6 @@ internal object Constants {
const val MISC_PATH = "$PATCHES_PATH/misc"
const val VIDEO_PATH = "$PATCHES_PATH/video"
const val UTILS_PATH = "$PATCHES_PATH/utils"
const val MUSIC_SETTINGS_PATH = "$INTEGRATIONS_PATH/settings/MusicSettings;"
}

View File

@ -1,6 +1,8 @@
package app.revanced.shared.util.resources
import app.revanced.patcher.data.ResourceContext
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import org.w3c.dom.Element
internal object ResourceHelper {
@ -203,6 +205,25 @@ internal object ResourceHelper {
)
}
fun addTranslations(
context: ResourceContext,
sourceDirectory: String,
languageArray: Array<String>
) {
languageArray.forEach { language ->
val directory = "values-$language-v21"
val relativePath = "$language/strings.xml"
context["res/$directory"].mkdir()
Files.copy(
this.javaClass.classLoader.getResourceAsStream("$sourceDirectory/translations/$relativePath")!!,
context["res"].resolve("$directory/strings.xml").toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
fun addReVancedSettings(
context: ResourceContext,
Preference: String