Skip to content

Commit

Permalink
fix(youtube/video-ads): add switch to temporarily fix buffering issues
Browse files Browse the repository at this point in the history
  • Loading branch information
oSumAtrIX committed Nov 1, 2022
1 parent f1e70d8 commit 6461877
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility
import app.revanced.patches.youtube.ad.video.fingerprints.LoadVideoAdsFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.playback.patch.FixPlaybackPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference

@Patch
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, FixPlaybackPatch::class])
@Name("video-ads")
@Description("Removes ads in the video player.")
@VideoAdsCompatibility
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,41 @@ import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.data.toMethodWalker
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.or
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.youtube.layout.autocaptions.fingerprints.StartVideoInformerFingerprint
import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility
import app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints.*
import app.revanced.patches.youtube.layout.sponsorblock.resource.patch.SponsorBlockResourcePatch
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.mapping.patch.ResourceMappingResourcePatch
import app.revanced.patches.youtube.misc.playercontroller.patch.PlayerControllerPatch
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
import app.revanced.patches.youtube.misc.videoid.patch.VideoIdPatch
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.MutableMethodImplementation
import org.jf.dexlib2.iface.instruction.*
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.MethodReference
import org.jf.dexlib2.iface.reference.StringReference
import org.jf.dexlib2.immutable.ImmutableMethod
import org.jf.dexlib2.immutable.ImmutableMethodParameter
import org.jf.dexlib2.util.MethodUtil

@Patch
@DependsOn(
dependencies = [PlayerControlsBytecodePatch::class, IntegrationsPatch::class, SponsorBlockResourcePatch::class, VideoIdPatch::class]
dependencies = [
PlayerControllerPatch::class, // updates video length and adds method to seek in video
PlayerControlsBytecodePatch::class,
IntegrationsPatch::class,
SponsorBlockResourcePatch::class,
VideoIdPatch::class
]
)
@Name("sponsorblock")
@Description("Integrate SponsorBlock.")
Expand All @@ -53,7 +54,6 @@ class SponsorBlockBytecodePatch : BytecodePatch(
VideoTimeFingerprint,
NextGenWatchLayoutFingerprint,
AppendTimeFingerprint,
PlayerInitFingerprint,
PlayerOverlaysLayoutInitFingerprint,
ShortsPlayerConstructorFingerprint,
StartVideoInformerFingerprint
Expand Down Expand Up @@ -160,23 +160,6 @@ class SponsorBlockBytecodePatch : BytecodePatch(
"invoke-static {v$canvasInstance, v$centerY}, Lapp/revanced/integrations/sponsorblock/PlayerController;->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V"
)

/*
Set video length
*/
VideoLengthFingerprint.resolve(context, seekbarSignatureResult.classDef)
val videoLengthMethodResult = VideoLengthFingerprint.result!!
val videoLengthMethod = videoLengthMethodResult.mutableMethod
val videoLengthMethodInstructions = videoLengthMethod.implementation!!.instructions

val videoLengthRegister =
(videoLengthMethodInstructions[videoLengthMethodResult.scanResult.patternScanResult!!.endIndex - 2] as OneRegisterInstruction).registerA
val dummyRegisterForLong =
videoLengthRegister + 1 // this is required for long values since they are 64 bit wide
videoLengthMethod.addInstruction(
videoLengthMethodResult.scanResult.patternScanResult!!.endIndex,
"invoke-static {v$videoLengthRegister, v$dummyRegisterForLong}, Lapp/revanced/integrations/sponsorblock/PlayerController;->setVideoLength(J)V"
)

/*
Voting & Shield button
*/
Expand Down Expand Up @@ -249,88 +232,46 @@ class SponsorBlockBytecodePatch : BytecodePatch(
)

// initialize the player controller
val initFingerprintResult = PlayerInitFingerprint.result!!
val initInstanceRegister = 0
initFingerprintResult.mutableClass.methods.first { MethodUtil.isConstructor(it) }.addInstruction(
4, // after super class invoke
"invoke-static {v$initInstanceRegister}, Lapp/revanced/integrations/sponsorblock/PlayerController;->onCreate(Ljava/lang/Object;)V"
)
PlayerControllerPatch.onCreateHook("Lapp/revanced/integrations/sponsorblock/PlayerController;", "initialize")

// initialize the sponsorblock view
PlayerOverlaysLayoutInitFingerprint.result!!.mutableMethod.addInstruction(
6, // after inflating the view
"invoke-static {p0}, Lapp/revanced/integrations/sponsorblock/player/ui/SponsorBlockView;->initialize(Ljava/lang/Object;)V"
)

// lastly create hooks for the player controller

// get original seek method
SeekFingerprint.resolve(context, initFingerprintResult.classDef)
val seekFingerprintResultMethod = SeekFingerprint.result!!.method
// get enum type for the seek helper method
val seekSourceEnumType = seekFingerprintResultMethod.parameterTypes[1].toString()

// create helper method
val seekHelperMethod = ImmutableMethod(
seekFingerprintResultMethod.definingClass,
"seekHelper",
listOf(ImmutableMethodParameter("J", null, "time")),
"Z",
AccessFlags.PUBLIC or AccessFlags.FINAL,
null, null,
MutableMethodImplementation(4)
).toMutable()

// insert helper method instructions
seekHelperMethod.addInstructions(
0,
"""
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
invoke-virtual {p0, p1, p2, v0}, ${seekFingerprintResultMethod.definingClass}->${seekFingerprintResultMethod.name}(J$seekSourceEnumType)Z
move-result p1
return p1
"""
)

// add the helper method to the original class
initFingerprintResult.mutableClass.methods.add(seekHelperMethod)

// get rectangle field name
RectangleFieldInvalidatorFingerprint.resolve(context, seekbarSignatureResult.classDef)
val rectangleFieldInvalidatorInstructions =
RectangleFieldInvalidatorFingerprint.result!!.method.implementation!!.instructions
val rectangleFieldName =
((rectangleFieldInvalidatorInstructions.elementAt(rectangleFieldInvalidatorInstructions.count() - 3) as ReferenceInstruction).reference as FieldReference).name

// get the player controller class from the integrations
val playerControllerMethods =
context.proxy(context.classes.first { it.type.endsWith("PlayerController;") }).mutableClass.methods

// get the method which contain the "replaceMe" strings
val replaceMeMethods =
playerControllerMethods.filter { it.name == "onCreate" || it.name == "setSponsorBarRect" }

fun MutableMethod.replaceStringInstruction(index: Int, instruction: Instruction, with: String) {
val register = (instruction as OneRegisterInstruction).registerA
this.replaceInstruction(
index, "const-string v$register, \"$with\""
)
}

// replace the "replaceMeWith*" strings
for (method in replaceMeMethods) {
for ((index, it) in method.implementation!!.instructions.withIndex()) {
if (it.opcode.ordinal != Opcode.CONST_STRING.ordinal) continue
context
.proxy(context.classes.first { it.type.endsWith("PlayerController;") })
.mutableClass
.methods
.find { it.name == "setSponsorBarRect" }
?.let { method ->
fun MutableMethod.replaceStringInstruction(index: Int, instruction: Instruction, with: String) {
val register = (instruction as OneRegisterInstruction).registerA
this.replaceInstruction(
index, "const-string v$register, \"$with\""
)
}
for ((index, it) in method.implementation!!.instructions.withIndex()) {
if (it.opcode.ordinal != Opcode.CONST_STRING.ordinal) continue

when (((it as ReferenceInstruction).reference as StringReference).string) {
"replaceMeWithsetSponsorBarRect" ->
method.replaceStringInstruction(index, it, rectangleFieldName)
when (((it as ReferenceInstruction).reference as StringReference).string) {
"replaceMeWithsetSponsorBarRect" ->
method.replaceStringInstruction(index, it, rectangleFieldName)

"replaceMeWithsetMillisecondMethod" ->
method.replaceStringInstruction(index, it, "seekHelper")
"replaceMeWithsetMillisecondMethod" ->
method.replaceStringInstruction(index, it, "seekHelper")
}
}
}
}
} ?: return PatchResultError("Could not find the method which contains the replaceMeWith* strings")

val startVideoInformerMethod = StartVideoInformerFingerprint.result!!.mutableMethod
startVideoInformerMethod.addInstructions(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package app.revanced.patches.youtube.misc.playback.annotations

import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package

@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.41.37")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class FixPlaybackCompatibility
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package app.revanced.patches.youtube.misc.playback.patch

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.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.playback.annotations.FixPlaybackCompatibility
import app.revanced.patches.youtube.misc.playercontroller.patch.PlayerControllerPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
import app.revanced.patches.youtube.misc.videoid.patch.VideoIdPatch

@DependsOn([
IntegrationsPatch::class,
PlayerControllerPatch::class, // updates video length and adds method to seek in video, necessary for this patch
SettingsPatch::class,
VideoIdPatch::class
])
@Name("fix-playback")
@Description("Fixes the issue with videos not playing when video ads are removed.")
@FixPlaybackCompatibility
@Version("0.0.1")
class FixPlaybackPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
SettingsPatch.PreferenceScreen.MISC.addPreferences(
SwitchPreference(
"revanced_fix_playback",
StringResource("revanced_fix_playback_title", "Fix video playback issues"),
false,
StringResource(
"revanced_fix_playback_summary_on",
"The fix is enabled"
),
StringResource(
"revanced_fix_playback_summary_off",
"The fix is disabled"
)
)
)

// If a new video loads, fix the playback issue
VideoIdPatch.injectCall("Lapp/revanced/integrations/patches/FixPlaybackPatch;->newVideoLoaded(Ljava/lang/String;)V")

return PatchResultSuccess()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package app.revanced.patches.youtube.misc.playercontroller.annotation

import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package

@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.41.37")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class PlayerControllerCompatibility
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package app.revanced.patches.youtube.misc.playercontroller.fingerprint

import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version

import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility

@Name("create-video-player-seekbar-fingerprint")
@SponsorBlockCompatibility
@Version("0.0.1")
object CreateVideoPlayerSeekbarFingerprint : MethodFingerprint(
"V",
strings = listOf("timed_markers_width")
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints
package app.revanced.patches.youtube.misc.playercontroller.fingerprint

import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints
package app.revanced.patches.youtube.misc.playercontroller.fingerprint

import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints
package app.revanced.patches.youtube.misc.playercontroller.fingerprint

import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
Expand Down
Loading

0 comments on commit 6461877

Please sign in to comment.