mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-02 15:44:37 +02:00
feat(music): add sponsorblock
patch https://github.com/inotia00/ReVanced_Extended/issues/97
This commit is contained in:
parent
31df1c67a6
commit
dec7dbe37b
@ -0,0 +1,10 @@
|
||||
package app.revanced.patches.music.utils.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch.Companion.InlineTimeBarAdBreakMarkerColor
|
||||
import app.revanced.util.bytecode.isWideLiteralExists
|
||||
|
||||
object SeekBarConstructorFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
customFingerprint = { methodDef, _ -> methodDef.isWideLiteralExists(InlineTimeBarAdBreakMarkerColor) }
|
||||
)
|
@ -22,6 +22,7 @@ class SharedResourceIdPatch : ResourcePatch {
|
||||
var ColorGrey: Long = -1
|
||||
var DialogSolid: Long = -1
|
||||
var DisabledIconAlpha: Long = -1
|
||||
var InlineTimeBarAdBreakMarkerColor: Long = -1
|
||||
var IsTablet: Long = -1
|
||||
var MusicMenuLikeButtons: Long = -1
|
||||
var MusicNotifierShelf: Long = -1
|
||||
@ -44,6 +45,7 @@ class SharedResourceIdPatch : ResourcePatch {
|
||||
ColorGrey = find(COLOR, "ytm_color_grey_12")
|
||||
DialogSolid = find(STYLE, "Theme.YouTubeMusic.Dialog.Solid")
|
||||
DisabledIconAlpha = find(DIMEN, "disabled_icon_alpha")
|
||||
InlineTimeBarAdBreakMarkerColor = find(COLOR, "inline_time_bar_ad_break_marker_color")
|
||||
IsTablet = find(BOOL, "is_tablet")
|
||||
MusicMenuLikeButtons = find(LAYOUT, "music_menu_like_buttons")
|
||||
MusicNotifierShelf = find(LAYOUT, "music_notifier_shelf")
|
||||
|
@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.music.utils.sponsorblock.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object MusicPlaybackControlsTimeBarDrawFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.definingClass.endsWith("/MusicPlaybackControlsTimeBar;")
|
||||
&& methodDef.name == "draw"
|
||||
}
|
||||
)
|
@ -0,0 +1,18 @@
|
||||
package app.revanced.patches.music.utils.sponsorblock.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
object MusicPlaybackControlsTimeBarOnMeasureFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.RETURN_VOID
|
||||
),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.definingClass.endsWith("/MusicPlaybackControlsTimeBar;")
|
||||
&& methodDef.name == "onMeasure"
|
||||
}
|
||||
)
|
@ -0,0 +1,7 @@
|
||||
package app.revanced.patches.music.utils.sponsorblock.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object SeekbarOnDrawFingerprint : MethodFingerprint(
|
||||
customFingerprint = { methodDef, _ -> methodDef.name == "onDraw" }
|
||||
)
|
@ -0,0 +1,177 @@
|
||||
package app.revanced.patches.music.utils.sponsorblock.bytecode.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.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.music.utils.fingerprints.SeekBarConstructorFingerprint
|
||||
import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch
|
||||
import app.revanced.patches.music.utils.sponsorblock.bytecode.fingerprints.MusicPlaybackControlsTimeBarDrawFingerprint
|
||||
import app.revanced.patches.music.utils.sponsorblock.bytecode.fingerprints.MusicPlaybackControlsTimeBarOnMeasureFingerprint
|
||||
import app.revanced.patches.music.utils.sponsorblock.bytecode.fingerprints.SeekbarOnDrawFingerprint
|
||||
import app.revanced.patches.music.utils.videoid.patch.VideoIdPatch
|
||||
import app.revanced.patches.music.utils.videoinformation.patch.VideoInformationPatch
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction3rc
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
@DependsOn(
|
||||
[
|
||||
SharedResourceIdPatch::class,
|
||||
VideoIdPatch::class,
|
||||
VideoInformationPatch::class
|
||||
]
|
||||
)
|
||||
class SponsorBlockBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
MusicPlaybackControlsTimeBarDrawFingerprint,
|
||||
MusicPlaybackControlsTimeBarOnMeasureFingerprint,
|
||||
SeekBarConstructorFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
/**
|
||||
* Hook the video time methods & Initialize the player controller
|
||||
*/
|
||||
VideoInformationPatch.apply {
|
||||
videoTimeHook(
|
||||
INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR,
|
||||
"setVideoTime"
|
||||
)
|
||||
onCreateHook(
|
||||
INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR,
|
||||
"initialize"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Responsible for seekbar in fullscreen
|
||||
*/
|
||||
SeekBarConstructorFingerprint.result?.classDef?.let { classDef ->
|
||||
SeekbarOnDrawFingerprint.also {
|
||||
it.resolve(
|
||||
context,
|
||||
classDef
|
||||
)
|
||||
}.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
// Initialize seekbar method
|
||||
addInstructions(
|
||||
0, """
|
||||
move-object/from16 v0, p0
|
||||
const-string v1, "${VideoInformationPatch.rectangleFieldName}"
|
||||
invoke-static {v0, v1}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;Ljava/lang/String;)V
|
||||
"""
|
||||
)
|
||||
|
||||
// Set seekbar thickness
|
||||
for ((index, instruction) in implementation!!.instructions.withIndex()) {
|
||||
if (instruction.opcode != Opcode.INVOKE_STATIC) continue
|
||||
|
||||
val invokeInstruction = getInstruction<Instruction35c>(index)
|
||||
if ((invokeInstruction.reference as MethodReference).name != "round") continue
|
||||
|
||||
val insertIndex = index + 2
|
||||
|
||||
addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static {v${invokeInstruction.registerC}}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarThickness(I)V"
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
// Draw segment
|
||||
for ((index, instruction) in implementation!!.instructions.withIndex()) {
|
||||
if (instruction.opcode != Opcode.INVOKE_VIRTUAL_RANGE) continue
|
||||
|
||||
val invokeInstruction = instruction as BuilderInstruction3rc
|
||||
if ((invokeInstruction.reference as MethodReference).name != "restore") continue
|
||||
|
||||
val drawSegmentInstructionInsertIndex = index - 1
|
||||
|
||||
val (canvasInstance, centerY) =
|
||||
getInstruction<FiveRegisterInstruction>(
|
||||
drawSegmentInstructionInsertIndex
|
||||
).let { drawSegmentInstruction ->
|
||||
drawSegmentInstruction.registerC to drawSegmentInstruction.registerE
|
||||
}
|
||||
|
||||
addInstruction(
|
||||
drawSegmentInstructionInsertIndex,
|
||||
"invoke-static {v$canvasInstance, v$centerY}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V"
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
} ?: throw SeekbarOnDrawFingerprint.exception
|
||||
} ?: throw SeekBarConstructorFingerprint.exception
|
||||
|
||||
|
||||
/**
|
||||
* Responsible for seekbar in player
|
||||
*/
|
||||
MusicPlaybackControlsTimeBarOnMeasureFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val rectangleIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val rectangleReference = getInstruction<ReferenceInstruction>(rectangleIndex).reference
|
||||
rectangleFieldName = (rectangleReference as FieldReference).name
|
||||
}
|
||||
} ?: throw MusicPlaybackControlsTimeBarOnMeasureFingerprint.exception
|
||||
|
||||
MusicPlaybackControlsTimeBarDrawFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
// Initialize seekbar method
|
||||
addInstructions(
|
||||
1, """
|
||||
move-object/from16 v0, p0
|
||||
const-string v1, "$rectangleFieldName"
|
||||
invoke-static {v0, v1}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;Ljava/lang/String;)V
|
||||
"""
|
||||
)
|
||||
|
||||
// Draw segment
|
||||
for ((index, instruction) in implementation!!.instructions.withIndex()) {
|
||||
if (instruction.opcode != Opcode.INVOKE_VIRTUAL) continue
|
||||
|
||||
val invokeInstruction = getInstruction<Instruction35c>(index)
|
||||
if ((invokeInstruction.reference as MethodReference).name != "drawCircle") continue
|
||||
|
||||
val (canvasInstance, centerY) =
|
||||
getInstruction<FiveRegisterInstruction>(
|
||||
index
|
||||
).let { drawSegmentInstruction ->
|
||||
drawSegmentInstruction.registerC to drawSegmentInstruction.registerE
|
||||
}
|
||||
|
||||
addInstruction(
|
||||
index,
|
||||
"invoke-static {v$canvasInstance, v$centerY}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V"
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
} ?: throw MusicPlaybackControlsTimeBarDrawFingerprint.exception
|
||||
|
||||
/**
|
||||
* Set current video id
|
||||
*/
|
||||
VideoIdPatch.injectCall("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/music/sponsorblock/SegmentPlaybackController;"
|
||||
|
||||
lateinit var rectangleFieldName: String
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package app.revanced.patches.music.utils.sponsorblock.resource.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
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.utils.annotations.MusicCompatibility
|
||||
import app.revanced.patches.music.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.music.utils.sponsorblock.bytecode.patch.SponsorBlockBytecodePatch
|
||||
import app.revanced.util.resources.MusicResourceHelper
|
||||
import app.revanced.util.resources.MusicResourceHelper.hookPreference
|
||||
import app.revanced.util.resources.ResourceUtils
|
||||
import app.revanced.util.resources.ResourceUtils.copyResources
|
||||
|
||||
@Patch
|
||||
@Name("SponsorBlock")
|
||||
@Description("Integrates SponsorBlock which allows skipping video segments such as sponsored content.")
|
||||
@DependsOn(
|
||||
[
|
||||
SettingsPatch::class,
|
||||
SponsorBlockBytecodePatch::class
|
||||
]
|
||||
)
|
||||
@MusicCompatibility
|
||||
class SponsorBlockPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext) {
|
||||
|
||||
/**
|
||||
* Copy preference
|
||||
*/
|
||||
arrayOf(
|
||||
ResourceUtils.ResourceGroup(
|
||||
"xml",
|
||||
"sponsorblock_prefs.xml"
|
||||
)
|
||||
).forEach { resourceGroup ->
|
||||
context.copyResources("music/sponsorblock", resourceGroup)
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook SponsorBlock preference
|
||||
*/
|
||||
context.hookPreference(
|
||||
"revanced_sponsorblock_settings",
|
||||
"com.google.android.apps.youtube.music.settings.fragment.AdvancedPrefsFragmentCompat"
|
||||
)
|
||||
|
||||
val publicFile = context["res/values/public.xml"]
|
||||
|
||||
publicFile.writeText(
|
||||
publicFile.readText()
|
||||
.replace(
|
||||
"\"advanced_prefs_compat\"",
|
||||
"\"sponsorblock_prefs\""
|
||||
)
|
||||
)
|
||||
|
||||
context["res/xml/sponsorblock_prefs.xml"].writeText(
|
||||
context["res/xml/sponsorblock_prefs.xml"].readText()
|
||||
.replace("\"com.google.android.apps.youtube.music\"", "\"" + MusicResourceHelper.targetPackage + "\"")
|
||||
)
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.music.utils.videoinformation.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
object PlayerControllerSetTimeReferenceFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_DIRECT_RANGE,
|
||||
Opcode.IGET_OBJECT
|
||||
),
|
||||
strings = listOf("Media progress reported outside media playback: ")
|
||||
)
|
@ -0,0 +1,7 @@
|
||||
package app.revanced.patches.music.utils.videoinformation.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object PlayerInitFingerprint : MethodFingerprint(
|
||||
strings = listOf("playVideo called on player response with no videoStreamingData."),
|
||||
)
|
@ -0,0 +1,7 @@
|
||||
package app.revanced.patches.music.utils.videoinformation.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object SeekFingerprint : MethodFingerprint(
|
||||
strings = listOf("Attempting to seek during an ad")
|
||||
)
|
@ -0,0 +1,17 @@
|
||||
package app.revanced.patches.music.utils.videoinformation.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
object VideoLengthFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT
|
||||
)
|
||||
)
|
@ -0,0 +1,170 @@
|
||||
package app.revanced.patches.music.utils.videoinformation.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.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.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patches.music.utils.annotations.MusicCompatibility
|
||||
import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch
|
||||
import app.revanced.patches.music.utils.videoinformation.fingerprints.PlayerControllerSetTimeReferenceFingerprint
|
||||
import app.revanced.patches.music.utils.videoinformation.fingerprints.PlayerInitFingerprint
|
||||
import app.revanced.patches.music.utils.fingerprints.SeekBarConstructorFingerprint
|
||||
import app.revanced.patches.music.utils.videoinformation.fingerprints.SeekFingerprint
|
||||
import app.revanced.patches.music.utils.videoinformation.fingerprints.VideoLengthFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
@Name("Video information")
|
||||
@Description("Hooks YouTube to get information about the current playing video.")
|
||||
@DependsOn(
|
||||
[
|
||||
SharedResourceIdPatch::class
|
||||
]
|
||||
)
|
||||
@MusicCompatibility
|
||||
class VideoInformationPatch : BytecodePatch(
|
||||
listOf(
|
||||
PlayerControllerSetTimeReferenceFingerprint,
|
||||
PlayerInitFingerprint,
|
||||
SeekBarConstructorFingerprint,
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
PlayerInitFingerprint.result?.let { parentResult ->
|
||||
playerInitMethod =
|
||||
parentResult.mutableClass.methods.first { MethodUtil.isConstructor(it) }
|
||||
|
||||
// hook the player controller for use through integrations
|
||||
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize")
|
||||
|
||||
SeekFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val seekHelperMethod = ImmutableMethod(
|
||||
definingClass,
|
||||
"seekTo",
|
||||
listOf(ImmutableMethodParameter("J", annotations, "time")),
|
||||
"Z",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
annotations, null,
|
||||
MutableMethodImplementation(4)
|
||||
).toMutable()
|
||||
|
||||
val seekSourceEnumType = parameterTypes[1].toString()
|
||||
|
||||
seekHelperMethod.addInstructions(
|
||||
0, """
|
||||
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
|
||||
invoke-virtual {p0, p1, p2, v0}, ${definingClass}->${name}(J$seekSourceEnumType)Z
|
||||
move-result p1
|
||||
return p1
|
||||
"""
|
||||
)
|
||||
|
||||
parentResult.mutableClass.methods.add(seekHelperMethod)
|
||||
}
|
||||
} ?: throw SeekFingerprint.exception
|
||||
} ?: throw PlayerInitFingerprint.exception
|
||||
|
||||
/**
|
||||
* Set current video length
|
||||
*/
|
||||
SeekBarConstructorFingerprint.result?.classDef?.let { classDef ->
|
||||
VideoLengthFingerprint.also {
|
||||
it.resolve(
|
||||
context,
|
||||
classDef
|
||||
)
|
||||
}.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val rectangleReference = getInstruction<ReferenceInstruction>(implementation!!.instructions.count() - 3).reference
|
||||
rectangleFieldName = (rectangleReference as FieldReference).name
|
||||
|
||||
val videoLengthRegisterIndex = it.scanResult.patternScanResult!!.startIndex + 1
|
||||
val videoLengthRegister = getInstruction<OneRegisterInstruction>(videoLengthRegisterIndex).registerA
|
||||
val dummyRegisterForLong = videoLengthRegister + 1 // required for long values since they are wide
|
||||
|
||||
addInstruction(
|
||||
videoLengthRegisterIndex + 1,
|
||||
"invoke-static {v$videoLengthRegister, v$dummyRegisterForLong}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V"
|
||||
)
|
||||
}
|
||||
} ?: throw VideoLengthFingerprint.exception
|
||||
} ?: throw SeekBarConstructorFingerprint.exception
|
||||
|
||||
/**
|
||||
* Set the video time method
|
||||
*/
|
||||
PlayerControllerSetTimeReferenceFingerprint.result?.let {
|
||||
timeMethod = context.toMethodWalker(it.method)
|
||||
.nextMethod(it.scanResult.patternScanResult!!.startIndex, true)
|
||||
.getMethod() as MutableMethod
|
||||
} ?: throw PlayerControllerSetTimeReferenceFingerprint.exception
|
||||
|
||||
/**
|
||||
* Set current video time
|
||||
*/
|
||||
videoTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime")
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/music/patches/utils/VideoInformation;"
|
||||
|
||||
private lateinit var playerInitMethod: MutableMethod
|
||||
private var playerInitInsertIndex = 4
|
||||
|
||||
private lateinit var timeMethod: MutableMethod
|
||||
private var timeInitInsertIndex = 2
|
||||
|
||||
lateinit var rectangleFieldName: String
|
||||
|
||||
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
|
||||
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
|
||||
|
||||
private fun MutableMethod.insertTimeHook(insertIndex: Int, descriptor: String) =
|
||||
insert(insertIndex, "p1, p2", descriptor)
|
||||
|
||||
/**
|
||||
* Hook the player controller. Called when a video is opened or the current video is changed.
|
||||
*
|
||||
* Note: This hook is called very early and is called before the video id, video time, video length,
|
||||
* and many other data fields are set.
|
||||
*
|
||||
* @param targetMethodClass The descriptor for the class to invoke when the player controller is created.
|
||||
* @param targetMethodName The name of the static method to invoke when the player controller is created.
|
||||
*/
|
||||
internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) =
|
||||
playerInitMethod.insert(
|
||||
playerInitInsertIndex++,
|
||||
"v0",
|
||||
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
|
||||
)
|
||||
|
||||
/**
|
||||
* Hook the video time.
|
||||
* The hook is usually called once per second.
|
||||
*
|
||||
* @param targetMethodClass The descriptor for the static method to invoke when the player controller is created.
|
||||
* @param targetMethodName The name of the static method to invoke when the player controller is created.
|
||||
*/
|
||||
internal fun videoTimeHook(targetMethodClass: String, targetMethodName: String) =
|
||||
timeMethod.insertTimeHook(
|
||||
timeInitInsertIndex++,
|
||||
"$targetMethodClass->$targetMethodName(J)V"
|
||||
)
|
||||
}
|
||||
}
|
@ -113,4 +113,57 @@
|
||||
<string name="revanced_save_video_quality_wifi">Changing default Wi-Fi quality to:</string>
|
||||
<string name="revanced_spoof_app_version_summary">Trick the YouTube Music version to v4.27.53 for Canadian users.</string>
|
||||
<string name="revanced_spoof_app_version_title">Spoof app version</string>
|
||||
|
||||
<string name="sb_enabled">Enable SponsorBlock</string>
|
||||
<string name="sb_enabled_sum">SponsorBlock is a crowd-sourced system for skipping annoying parts of YouTube videos.</string>
|
||||
|
||||
<string name="sb_toast_on_skip">Show a toast when skipping automatically</string>
|
||||
<string name="sb_toast_on_skip_sum">Toast shown when a segment is automatically skipped.</string>
|
||||
|
||||
<string name="sb_api_url">Change API URL</string>
|
||||
<string name="sb_api_url_sum">The address SponsorBlock uses to make calls to the server. Do not change this unless you know what you\'re doing</string>
|
||||
<string name="sb_api_url_reset">API URL reset</string>
|
||||
<string name="sb_api_url_invalid">API URL is invalid</string>
|
||||
<string name="sb_api_url_changed">API URL changed</string>
|
||||
|
||||
<string name="sb_diff_segments">Change segment behavior</string>
|
||||
<string name="sb_segments_sponsor">Sponsor</string>
|
||||
<string name="sb_segments_sponsor_sum">Paid promotion, paid referrals and direct advertisements. Not for self-promotion or free shout-outs to causes/creators/websites/products they like</string>
|
||||
<string name="sb_segments_selfpromo">Unpaid / Self Promotion</string>
|
||||
<string name="sb_segments_selfpromo_sum">Similar to \'Sponsor\' except for unpaid or self promotion. Includes sections about merchandise, donations, or information about who they collaborated with</string>
|
||||
<string name="sb_segments_interaction">Interaction Reminder (Subscribe)</string>
|
||||
<string name="sb_segments_interaction_sum">A short reminder to like, subscribe or follow them in the middle of content. If it is long or about something specific, it should instead be under self promotion</string>
|
||||
<string name="sb_segments_intro">Intermission / Intro Animation</string>
|
||||
<string name="sb_segments_intro_sum">An interval without actual content. Could be a pause, static frame, or repeating animation. Does not include transitions containing information</string>
|
||||
<string name="sb_segments_outro">Endcards / Credits</string>
|
||||
<string name="sb_segments_outro_sum">Credits or when the YouTube endcards appear. Not for conclusions with information</string>
|
||||
<string name="sb_segments_preview">Preview / Recap</string>
|
||||
<string name="sb_segments_preview_sum">Collection of clips that show what is coming up or what happened in the video or in other videos of a series, where all information is repeated elsewhere</string>
|
||||
<string name="sb_segments_filler">Filler Tangent / Jokes</string>
|
||||
<string name="sb_segments_filler_sum">Tangential scenes added only for filler or humor that are not required to understand the main content of the video. Does not include segments providing context or background details</string>
|
||||
<string name="sb_segments_nomusic">Music: Non-Music Section</string>
|
||||
<string name="sb_segments_nomusic_sum">Only for use in music videos. Sections of music videos without music, that aren\'t already covered by another category</string>
|
||||
|
||||
<string name="sb_skipped_sponsor">Skipped sponsor</string>
|
||||
<string name="sb_skipped_selfpromo">Skipped self promotion</string>
|
||||
<string name="sb_skipped_interaction">Skipped annoying reminder</string>
|
||||
<string name="sb_skipped_intro_beginning">Skipped intro</string>
|
||||
<string name="sb_skipped_intro_middle">Skipped intermission</string>
|
||||
<string name="sb_skipped_intro_end">Skipped intermission</string>
|
||||
<string name="sb_skipped_outro">Skipped outro</string>
|
||||
<string name="sb_skipped_preview_beginning">Skipped preview</string>
|
||||
<string name="sb_skipped_preview_middle">Skipped preview</string>
|
||||
<string name="sb_skipped_preview_end">Skipped recap</string>
|
||||
<string name="sb_skipped_filler">Skipped filler</string>
|
||||
<string name="sb_skipped_nomusic">Skipped a non-music section</string>
|
||||
<string name="sb_skipped_multiple_segments">Skipped multiple segments</string>
|
||||
<string name="sb_skip_automatically">Skip automatically</string>
|
||||
<string name="sb_skip_ignore">Disable</string>
|
||||
|
||||
<string name="sb_color_dot_label">Color:</string>
|
||||
<string name="sb_color_changed">Color changed</string>
|
||||
<string name="sb_color_reset">Color reset</string>
|
||||
<string name="sb_color_invalid">Invalid color code</string>
|
||||
<string name="sb_reset_color">Reset color</string>
|
||||
<string name="sb_about_api_sum">Data is provided by the SponsorBlock API. Tap here to learn more and see downloads for other platforms</string>
|
||||
</resources>
|
||||
|
@ -4,4 +4,7 @@
|
||||
<string name="revanced_extended_settings_title">ReVanced Extended</string>
|
||||
<string name="revanced_ryd_enabled_title">@string/revanced_ryd_settings_title</string>
|
||||
<string name="revanced_ryd_settings_title">Return YouTube Dislike</string>
|
||||
<string name="revanced_sponsorblock_settings_title">SponsorBlock</string>
|
||||
<string name="sb_about">@string/revanced_ryd_about</string>
|
||||
<string name="sb_about_api">sponsor.ajay.app</string>
|
||||
</resources>
|
||||
|
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:yt="http://schemas.android.com/apk/res-auto">
|
||||
<com.google.android.apps.youtube.music.ui.preference.SwitchCompatPreference android:title="@string/sb_enabled" android:key="sb_enabled" android:summary="@string/sb_enabled_sum" android:defaultValue="true" />
|
||||
<com.google.android.apps.youtube.music.ui.preference.SwitchCompatPreference android:title="@string/sb_toast_on_skip" android:key="sb_toast_on_skip" android:summary="@string/sb_toast_on_skip_sum" android:dependency="sb_enabled" android:defaultValue="true" />
|
||||
<Preference android:title="@string/sb_api_url" android:key="sb_api_url" android:summary="@string/sb_api_url_sum" android:dependency="sb_enabled">
|
||||
<intent android:targetPackage="com.google.android.apps.youtube.music" android:data="sb_api_url" android:targetClass="com.google.android.libraries.strictmode.penalties.notification.FullStackTraceActivity" />
|
||||
</Preference>
|
||||
<com.google.android.apps.youtube.music.ui.preference.PreferenceCategoryCompat android:title="@string/sb_diff_segments" android:key="segments">
|
||||
<Preference android:title="@string/sb_segments_sponsor" android:key="sb_segments_sponsor" android:summary="@string/sb_segments_sponsor_sum">
|
||||
<intent android:targetPackage="com.google.android.apps.youtube.music" android:data="sb_segments_sponsor" android:targetClass="com.google.android.libraries.strictmode.penalties.notification.FullStackTraceActivity" />
|
||||
</Preference>
|
||||
<Preference android:title="@string/sb_segments_selfpromo" android:key="sb_segments_selfpromo" android:summary="@string/sb_segments_selfpromo_sum">
|
||||
<intent android:targetPackage="com.google.android.apps.youtube.music" android:data="sb_segments_selfpromo" android:targetClass="com.google.android.libraries.strictmode.penalties.notification.FullStackTraceActivity" />
|
||||
</Preference>
|
||||
<Preference android:title="@string/sb_segments_interaction" android:key="sb_segments_interaction" android:summary="@string/sb_segments_interaction_sum">
|
||||
<intent android:targetPackage="com.google.android.apps.youtube.music" android:data="sb_segments_interaction" android:targetClass="com.google.android.libraries.strictmode.penalties.notification.FullStackTraceActivity" />
|
||||
</Preference>
|
||||
<Preference android:title="@string/sb_segments_intro" android:key="sb_segments_intro" android:summary="@string/sb_segments_intro_sum">
|
||||
<intent android:targetPackage="com.google.android.apps.youtube.music" android:data="sb_segments_intro" android:targetClass="com.google.android.libraries.strictmode.penalties.notification.FullStackTraceActivity" />
|
||||
</Preference>
|
||||
<Preference android:title="@string/sb_segments_outro" android:key="sb_segments_outro" android:summary="@string/sb_segments_outro_sum">
|
||||
<intent android:targetPackage="com.google.android.apps.youtube.music" android:data="sb_segments_outro" android:targetClass="com.google.android.libraries.strictmode.penalties.notification.FullStackTraceActivity" />
|
||||
</Preference>
|
||||
<Preference android:title="@string/sb_segments_preview" android:key="sb_segments_preview" android:summary="@string/sb_segments_preview_sum">
|
||||
<intent android:targetPackage="com.google.android.apps.youtube.music" android:data="sb_segments_preview" android:targetClass="com.google.android.libraries.strictmode.penalties.notification.FullStackTraceActivity" />
|
||||
</Preference>
|
||||
<Preference android:title="@string/sb_segments_filler" android:key="sb_segments_filler" android:summary="@string/sb_segments_filler_sum">
|
||||
<intent android:targetPackage="com.google.android.apps.youtube.music" android:data="sb_segments_filler" android:targetClass="com.google.android.libraries.strictmode.penalties.notification.FullStackTraceActivity" />
|
||||
</Preference>
|
||||
<Preference android:title="@string/sb_segments_nomusic" android:key="sb_segments_music_offtopic" android:summary="@string/sb_segments_nomusic_sum">
|
||||
<intent android:targetPackage="com.google.android.apps.youtube.music" android:data="sb_segments_music_offtopic" android:targetClass="com.google.android.libraries.strictmode.penalties.notification.FullStackTraceActivity" />
|
||||
</Preference>
|
||||
</com.google.android.apps.youtube.music.ui.preference.PreferenceCategoryCompat>
|
||||
<com.google.android.apps.youtube.music.ui.preference.PreferenceCategoryCompat android:title="@string/sb_about" android:key="about">
|
||||
<Preference android:title="@string/sb_about_api" android:key="sb_about_api" android:summary="@string/sb_about_api_sum">
|
||||
<intent android:action="android.intent.action.VIEW" android:data="https://sponsor.ajay.app" />
|
||||
</Preference>
|
||||
</com.google.android.apps.youtube.music.ui.preference.PreferenceCategoryCompat>
|
||||
</PreferenceScreen>
|
Loading…
x
Reference in New Issue
Block a user