mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-22 19:09:12 +02:00
feat(music): add enable playback speed
patch
This commit is contained in:
parent
a25d4be63e
commit
63628d6f75
@ -0,0 +1,15 @@
|
||||
package app.revanced.patches.music.flyoutpanel.playbackspeed.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch.Companion.MusicMenuLikeButtons
|
||||
import app.revanced.util.bytecode.isWideLiteralExists
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
object FlyoutPanelLikeButtonFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.SYNTHETIC,
|
||||
parameters = listOf("L", "Ljava/lang/Object;"),
|
||||
customFingerprint = { methodDef, _ -> methodDef.isWideLiteralExists(MusicMenuLikeButtons) }
|
||||
)
|
||||
|
@ -0,0 +1,72 @@
|
||||
package app.revanced.patches.music.flyoutpanel.playbackspeed.patch
|
||||
|
||||
import app.revanced.extensions.exception
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.music.flyoutpanel.playbackspeed.fingerprints.FlyoutPanelLikeButtonFingerprint
|
||||
import app.revanced.patches.music.utils.annotations.MusicCompatibility
|
||||
import app.revanced.patches.music.utils.flyoutbuttonhook.patch.FlyoutButtonHookPatch
|
||||
import app.revanced.patches.music.utils.overridespeed.patch.OverrideSpeedHookPatch
|
||||
import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch
|
||||
import app.revanced.patches.music.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.bytecode.getWideLiteralIndex
|
||||
import app.revanced.util.enum.CategoryType
|
||||
import app.revanced.util.integrations.Constants.MUSIC_FLYOUT
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch
|
||||
@Name("Enable playback speed")
|
||||
@Description("Add playback speed button to the flyout panel.")
|
||||
@DependsOn(
|
||||
[
|
||||
FlyoutButtonHookPatch::class,
|
||||
OverrideSpeedHookPatch::class,
|
||||
SettingsPatch::class,
|
||||
SharedResourceIdPatch::class
|
||||
]
|
||||
)
|
||||
@MusicCompatibility
|
||||
class PlaybackSpeedPatch : BytecodePatch(
|
||||
listOf(FlyoutPanelLikeButtonFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
FlyoutPanelLikeButtonFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex = getWideLiteralIndex(SharedResourceIdPatch.MusicMenuLikeButtons)
|
||||
|
||||
var insertIndex = -1
|
||||
|
||||
for (index in targetIndex until targetIndex + 5) {
|
||||
if (getInstruction(index).opcode != Opcode.MOVE_RESULT_OBJECT) continue
|
||||
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
insertIndex = index
|
||||
|
||||
addInstruction(
|
||||
index + 1,
|
||||
"invoke-static {v$register}, $MUSIC_FLYOUT->setFlyoutButtonContainer(Landroid/view/View;)V"
|
||||
)
|
||||
break
|
||||
}
|
||||
if (insertIndex == -1)
|
||||
throw PatchException("Couldn't find target Index")
|
||||
}
|
||||
} ?: throw FlyoutPanelLikeButtonFingerprint.exception
|
||||
|
||||
SettingsPatch.addMusicPreference(
|
||||
CategoryType.FLYOUT,
|
||||
"revanced_enable_flyout_panel_playback_speed",
|
||||
"false"
|
||||
)
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package app.revanced.patches.music.utils.flyoutbuttonhook.patch
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.util.resources.ResourceUtils
|
||||
import app.revanced.util.resources.ResourceUtils.copyResources
|
||||
|
||||
class FlyoutButtonHookPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext) {
|
||||
|
||||
/**
|
||||
* create directory for flyout button container
|
||||
*/
|
||||
context["res/layout-v21"].mkdirs()
|
||||
|
||||
arrayOf(
|
||||
ResourceUtils.ResourceGroup(
|
||||
"layout-v21",
|
||||
"music_menu_like_buttons.xml"
|
||||
)
|
||||
).forEach { resourceGroup ->
|
||||
context.copyResources("music/flyout", resourceGroup)
|
||||
}
|
||||
|
||||
fun copyResources(resourceGroups: List<ResourceUtils.ResourceGroup>) {
|
||||
resourceGroups.forEach { context.copyResources("music/flyout", it) }
|
||||
}
|
||||
|
||||
fun createGroup(directory: String) = ResourceUtils.ResourceGroup(
|
||||
directory, "yt_outline_play_arrow_half_circle_black_24.png"
|
||||
)
|
||||
|
||||
arrayOf("xxxhdpi", "xxhdpi", "xhdpi", "hdpi", "mdpi")
|
||||
.map { "drawable-$it" }
|
||||
.map(::createGroup)
|
||||
.let(::copyResources)
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package app.revanced.patches.music.utils.overridespeed.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
object PlaybackSpeedFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||
parameters = emptyList(),
|
||||
opcodes = listOf(
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.CONST_HIGH16,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
)
|
||||
)
|
@ -0,0 +1,12 @@
|
||||
package app.revanced.patches.music.utils.overridespeed.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
object PlaybackSpeedParentFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||
parameters = emptyList(),
|
||||
strings = listOf("BT metadata: %s, %s, %s")
|
||||
)
|
@ -0,0 +1,15 @@
|
||||
package app.revanced.patches.music.utils.overridespeed.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
object PlaybackSpeedPatchFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
parameters = listOf("F"),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.definingClass == "Lapp/revanced/music/patches/misc/PlaybackSpeedPatch;"
|
||||
&& methodDef.name == "overrideSpeed"
|
||||
}
|
||||
)
|
@ -0,0 +1,114 @@
|
||||
package app.revanced.patches.music.utils.overridespeed.patch
|
||||
|
||||
import app.revanced.extensions.exception
|
||||
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.getInstruction
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.music.utils.overridespeed.fingerprints.PlaybackSpeedFingerprint
|
||||
import app.revanced.patches.music.utils.overridespeed.fingerprints.PlaybackSpeedParentFingerprint
|
||||
import app.revanced.patches.music.utils.overridespeed.fingerprints.PlaybackSpeedPatchFingerprint
|
||||
import app.revanced.util.integrations.Constants.MUSIC_INTEGRATIONS_PATH
|
||||
import app.revanced.util.integrations.Constants.MUSIC_MISC_PATH
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c
|
||||
import com.android.tools.smali.dexlib2.dexbacked.reference.DexBackedMethodReference
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.Reference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableField
|
||||
|
||||
class OverrideSpeedHookPatch : BytecodePatch(
|
||||
listOf(
|
||||
PlaybackSpeedPatchFingerprint,
|
||||
PlaybackSpeedParentFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
PlaybackSpeedParentFingerprint.result?.let { parentResult ->
|
||||
val parentClassDef = parentResult.classDef
|
||||
|
||||
PlaybackSpeedFingerprint.also {
|
||||
it.resolve(
|
||||
context,
|
||||
parentClassDef
|
||||
)
|
||||
}.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
val speedClassRegister =
|
||||
getInstruction<OneRegisterInstruction>(startIndex).registerA
|
||||
val speedRegister =
|
||||
getInstruction<OneRegisterInstruction>(startIndex + 1).registerA
|
||||
|
||||
SPEED_REFERENCE = getInstruction<BuilderInstruction35c>(endIndex).reference
|
||||
SPEED_CLASS = (SPEED_REFERENCE as DexBackedMethodReference).definingClass
|
||||
|
||||
with(
|
||||
context
|
||||
.toMethodWalker(this)
|
||||
.nextMethod(endIndex, true)
|
||||
.getMethod() as MutableMethod
|
||||
) {
|
||||
addInstruction(
|
||||
this.implementation!!.instructions.size - 1,
|
||||
"sput p1, $INTEGRATIONS_VIDEO_HELPER_CLASS_DESCRIPTOR->currentSpeed:F"
|
||||
)
|
||||
}
|
||||
|
||||
addInstructions(
|
||||
startIndex + 2, """
|
||||
sput-object v$speedClassRegister, $INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->speedClass:$SPEED_CLASS
|
||||
invoke-static {}, $INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->getPlaybackSpeed()F
|
||||
move-result v$speedRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
} ?: throw PlaybackSpeedFingerprint.exception
|
||||
} ?: throw PlaybackSpeedParentFingerprint.exception
|
||||
|
||||
PlaybackSpeedPatchFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
it.mutableClass.staticFields.add(
|
||||
ImmutableField(
|
||||
definingClass,
|
||||
"speedClass",
|
||||
SPEED_CLASS,
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
null,
|
||||
annotations,
|
||||
null
|
||||
).toMutable()
|
||||
)
|
||||
|
||||
addInstructions(
|
||||
4, """
|
||||
sget-object v0, $INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->speedClass:$SPEED_CLASS
|
||||
invoke-virtual {v0, p0}, $SPEED_REFERENCE
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
} ?: throw PlaybackSpeedPatchFingerprint.exception
|
||||
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
const val INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR =
|
||||
"$MUSIC_MISC_PATH/PlaybackSpeedPatch;"
|
||||
|
||||
const val INTEGRATIONS_VIDEO_HELPER_CLASS_DESCRIPTOR =
|
||||
"$MUSIC_INTEGRATIONS_PATH/utils/VideoHelpers;"
|
||||
|
||||
private lateinit var SPEED_CLASS: String
|
||||
private lateinit var SPEED_REFERENCE: Reference
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ class SharedResourceIdPatch : ResourcePatch {
|
||||
var DialogSolid: Long = -1
|
||||
var DisabledIconAlpha: Long = -1
|
||||
var IsTablet: Long = -1
|
||||
var MusicMenuLikeButtons: Long = -1
|
||||
var MusicNotifierShelf: Long = -1
|
||||
var PrivacyTosFooter: Long = -1
|
||||
var QualityTitle: Long = -1
|
||||
@ -43,6 +44,7 @@ class SharedResourceIdPatch : ResourcePatch {
|
||||
DialogSolid = find(STYLE, "Theme.YouTubeMusic.Dialog.Solid")
|
||||
DisabledIconAlpha = find(DIMEN, "disabled_icon_alpha")
|
||||
IsTablet = find(BOOL, "is_tablet")
|
||||
MusicMenuLikeButtons = find(LAYOUT, "music_menu_like_buttons")
|
||||
MusicNotifierShelf = find(LAYOUT, "music_notifier_shelf")
|
||||
PrivacyTosFooter = find(ID, "privacy_tos_footer")
|
||||
QualityTitle = find(STRING, "quality_title")
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 449 B |
Binary file not shown.
After Width: | Height: | Size: 295 B |
Binary file not shown.
After Width: | Height: | Size: 584 B |
Binary file not shown.
After Width: | Height: | Size: 881 B |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<com.google.android.libraries.youtube.common.ui.TouchImageView android:id="@+id/playback_speed_button" android:padding="@dimen/remix_overlay_player_control_button_padding" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/yt_outline_play_arrow_half_circle_black_24" android:tint="@color/ytm_icon_color_active" android:contentDescription="@string/action_add_to_offline_songs" style="@style/MusicPlayerButton" />
|
||||
<com.google.android.libraries.youtube.common.ui.TouchImageView android:id="@id/dislike_button" android:padding="@dimen/remix_overlay_player_control_button_padding" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ytdislike_drawable" android:tint="@color/ytm_icon_color_active" android:contentDescription="@string/accessibility_dislike_video" style="@style/MusicPlayerButton" />
|
||||
<com.google.android.libraries.youtube.common.ui.TouchImageView android:id="@id/like_button" android:padding="@dimen/remix_overlay_player_control_button_padding" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ytlike_drawable" android:tint="@color/ytm_icon_color_active" android:contentDescription="@string/accessibility_like_video" style="@style/MusicPlayerButton" />
|
||||
</LinearLayout>
|
@ -22,6 +22,8 @@
|
||||
<string name="revanced_enable_compact_dialog_title">Enable compact dialog</string>
|
||||
<string name="revanced_enable_debug_logging_summary">Prints the debug log</string>
|
||||
<string name="revanced_enable_debug_logging_title">Enable debug logging</string>
|
||||
<string name="revanced_enable_flyout_panel_playback_speed_summary">Add an playback speed button to the flyout panel.</string>
|
||||
<string name="revanced_enable_flyout_panel_playback_speed_title">Enable playback speed</string>
|
||||
<string name="revanced_enable_force_minimized_player_summary">Keep player permanently minimized even if another track is played.</string>
|
||||
<string name="revanced_enable_force_minimized_player_title">Enable force minimized player</string>
|
||||
<string name="revanced_enable_force_shuffle_summary">Enable force shuffle even if another track is played.</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user