Skip to content

Commit 317e9a8

Browse files
author
LisoUseInAIKyrios
authored
fix(YouTube): Show video chapter titles without clipping when overlay buttons are enabled (#3674)
1 parent 464e6a3 commit 317e9a8

File tree

41 files changed

+530
-266
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+530
-266
lines changed

api/revanced-patches.api

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2000,13 +2000,19 @@ public final class app/revanced/patches/youtube/misc/playercontrols/BottomContro
20002000

20012001
public final class app/revanced/patches/youtube/misc/playercontrols/PlayerControlsBytecodePatch : app/revanced/patcher/patch/BytecodePatch {
20022002
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/playercontrols/PlayerControlsBytecodePatch;
2003-
public static field showPlayerControlsFingerprintResult Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;
20042003
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
20052004
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
2006-
public final fun getShowPlayerControlsFingerprintResult ()Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;
2005+
public final fun initializeBottomControl (Ljava/lang/String;)V
20072006
public final fun initializeControl (Ljava/lang/String;)V
20082007
public final fun injectVisibilityCheckCall (Ljava/lang/String;)V
2009-
public final fun setShowPlayerControlsFingerprintResult (Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;)V
2008+
}
2009+
2010+
public final class app/revanced/patches/youtube/misc/playercontrols/PlayerControlsResourcePatch : app/revanced/patcher/patch/ResourcePatch, java/io/Closeable {
2011+
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/playercontrols/PlayerControlsResourcePatch;
2012+
public final fun addBottomControls (Ljava/lang/String;)V
2013+
public fun close ()V
2014+
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
2015+
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
20102016
}
20112017

20122018
public final class app/revanced/patches/youtube/misc/playeroverlay/PlayerOverlaysHookPatch : app/revanced/patcher/patch/BytecodePatch {
@@ -2174,6 +2180,8 @@ public final class app/revanced/util/BytecodeUtilsKt {
21742180
public static synthetic fun indexOfFirstInstructionOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
21752181
public static final fun indexOfFirstWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
21762182
public static final fun indexOfFirstWideLiteralInstructionValueOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
2183+
public static final fun indexOfFirstWideLiteralInstructionValueReversed (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
2184+
public static final fun indexOfFirstWideLiteralInstructionValueReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
21772185
public static final fun indexOfIdResource (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
21782186
public static final fun indexOfIdResourceOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
21792187
public static final fun injectHideViewCall (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;IILjava/lang/String;Ljava/lang/String;)V
@@ -2201,6 +2209,7 @@ public final class app/revanced/util/ResourceUtilsKt {
22012209
public static final fun copyXmlNode (Ljava/lang/String;Lapp/revanced/patcher/util/DomFileEditor;Lapp/revanced/patcher/util/DomFileEditor;)Ljava/lang/AutoCloseable;
22022210
public static final fun doRecursively (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V
22032211
public static final fun forEachChildElement (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V
2212+
public static final fun insertFirst (Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)V
22042213
public static final fun iterateXmlNodeChildren (Lapp/revanced/patcher/data/ResourceContext;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
22052214
}
22062215

src/main/kotlin/app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import app.revanced.patches.shared.misc.settings.preference.IntentPreference
99
import app.revanced.util.ResourceGroup
1010
import app.revanced.util.copyResources
1111
import app.revanced.util.getNode
12+
import app.revanced.util.insertFirst
1213
import org.w3c.dom.Node
1314
import java.io.Closeable
1415

@@ -47,11 +48,7 @@ abstract class BaseSettingsResourcePatch(
4748
// It may be necessary to ask for the desired resourceValue in the future.
4849
AddResourcesPatch("values", resource)
4950
}.let { preferenceNode ->
50-
if (prepend && firstChild != null) {
51-
insertBefore(preferenceNode, firstChild)
52-
} else {
53-
appendChild(preferenceNode)
54-
}
51+
insertFirst(preferenceNode)
5552
}
5653
}
5754

src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ object CopyVideoUrlBytecodePatch : BytecodePatch(emptySet()) {
5151

5252
override fun execute(context: BytecodeContext) {
5353
BUTTONS_DESCRIPTORS.forEach { descriptor ->
54-
PlayerControlsBytecodePatch.initializeControl("$descriptor->initializeButton(Landroid/view/View;)V")
55-
PlayerControlsBytecodePatch.injectVisibilityCheckCall("$descriptor->changeVisibility(Z)V")
54+
PlayerControlsBytecodePatch.initializeBottomControl(descriptor)
55+
PlayerControlsBytecodePatch.injectVisibilityCheckCall(descriptor)
5656
}
5757
}
5858
}

src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlResourcePatch.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import app.revanced.patcher.patch.ResourcePatch
55
import app.revanced.patcher.patch.annotation.Patch
66
import app.revanced.patches.all.misc.resources.AddResourcesPatch
77
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
8-
import app.revanced.patches.youtube.misc.playercontrols.BottomControlsResourcePatch
8+
import app.revanced.patches.youtube.misc.playercontrols.PlayerControlsResourcePatch
99
import app.revanced.patches.youtube.misc.settings.SettingsPatch
1010
import app.revanced.util.ResourceGroup
1111
import app.revanced.util.copyResources
1212

1313
@Patch(
1414
dependencies = [
1515
SettingsPatch::class,
16-
BottomControlsResourcePatch::class,
16+
PlayerControlsResourcePatch::class,
1717
AddResourcesPatch::class
1818
]
1919
)
@@ -34,6 +34,6 @@ internal object CopyVideoUrlResourcePatch : ResourcePatch() {
3434
)
3535
)
3636

37-
BottomControlsResourcePatch.addControls("copyvideourl")
37+
PlayerControlsResourcePatch.addBottomControls("copyvideourl")
3838
}
3939
}

src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ object DownloadsPatch : BytecodePatch(
5858
private const val BUTTON_DESCRIPTOR = "Lapp/revanced/integrations/youtube/videoplayer/ExternalDownloadButton;"
5959

6060
override fun execute(context: BytecodeContext) {
61-
PlayerControlsBytecodePatch.initializeControl("$BUTTON_DESCRIPTOR->initializeButton(Landroid/view/View;)V")
62-
PlayerControlsBytecodePatch.injectVisibilityCheckCall("$BUTTON_DESCRIPTOR->changeVisibility(Z)V")
61+
PlayerControlsBytecodePatch.initializeBottomControl(BUTTON_DESCRIPTOR)
62+
PlayerControlsBytecodePatch.injectVisibilityCheckCall(BUTTON_DESCRIPTOR)
6363

6464
// Main activity is used to launch downloader intent.
6565
MainActivityFingerprint.resultOrThrow().mutableMethod.apply {

src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsResourcePatch.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
99
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
1010
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
1111
import app.revanced.patches.shared.misc.settings.preference.TextPreference
12-
import app.revanced.patches.youtube.misc.playercontrols.BottomControlsResourcePatch
12+
import app.revanced.patches.youtube.misc.playercontrols.PlayerControlsResourcePatch
1313
import app.revanced.patches.youtube.misc.settings.SettingsPatch
1414
import app.revanced.util.ResourceGroup
1515
import app.revanced.util.copyResources
1616

1717
@Patch(
1818
dependencies = [
19-
BottomControlsResourcePatch::class,
19+
PlayerControlsResourcePatch::class,
2020
SettingsPatch::class,
2121
AddResourcesPatch::class,
2222
],
@@ -42,6 +42,6 @@ internal object DownloadsResourcePatch : ResourcePatch() {
4242
ResourceGroup("drawable", "revanced_yt_download_button.xml"),
4343
)
4444

45-
BottomControlsResourcePatch.addControls("downloads")
45+
PlayerControlsResourcePatch.addBottomControls("downloads")
4646
}
4747
}

src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockBytecodePatch.kt

Lines changed: 10 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import app.revanced.patcher.patch.PatchException
1010
import app.revanced.patcher.patch.annotation.CompatiblePackage
1111
import app.revanced.patcher.patch.annotation.Patch
1212
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
13-
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
1413
import app.revanced.patches.youtube.layout.sponsorblock.fingerprints.AppendTimeFingerprint
1514
import app.revanced.patches.youtube.layout.sponsorblock.fingerprints.ControlsOverlayFingerprint
1615
import app.revanced.patches.youtube.layout.sponsorblock.fingerprints.RectangleFieldInvalidatorFingerprint
@@ -26,7 +25,10 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch
2625
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
2726
import app.revanced.util.exception
2827
import com.android.tools.smali.dexlib2.Opcode
29-
import com.android.tools.smali.dexlib2.iface.instruction.*
28+
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
29+
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
30+
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
31+
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
3032
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
3133
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
3234
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@@ -169,59 +171,14 @@ object SponsorBlockBytecodePatch : BytecodePatch(
169171
break
170172
}
171173

172-
/*
173-
* Voting & Shield button
174-
*/
175-
val controlsMethodResult = PlayerControlsBytecodePatch.showPlayerControlsFingerprintResult
176-
177-
val controlsLayoutStubResourceId =
178-
ResourceMappingPatch["id", "controls_layout_stub"]
179-
val zoomOverlayResourceId =
180-
ResourceMappingPatch["id", "video_zoom_overlay_stub"]
181-
182-
methods@ for (method in controlsMethodResult.mutableClass.methods) {
183-
val instructions = method.implementation?.instructions!!
184-
instructions@ for ((index, instruction) in instructions.withIndex()) {
185-
// search for method which inflates the controls layout view
186-
if (instruction.opcode != Opcode.CONST) continue@instructions
187-
188-
when ((instruction as NarrowLiteralInstruction).wideLiteral) {
189-
controlsLayoutStubResourceId -> {
190-
// replace the view with the YouTubeControlsOverlay
191-
val moveResultInstructionIndex = index + 5
192-
val inflatedViewRegister =
193-
(instructions[moveResultInstructionIndex] as OneRegisterInstruction).registerA
194-
// initialize with the player overlay object
195-
method.addInstructions(
196-
moveResultInstructionIndex + 1, // insert right after moving the view to the register and use that register
197-
"""
198-
invoke-static {v$inflatedViewRegister}, $INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->initialize(Landroid/view/View;)V
199-
invoke-static {v$inflatedViewRegister}, $INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->initialize(Landroid/view/View;)V
200-
""",
201-
)
202-
}
203-
204-
zoomOverlayResourceId -> {
205-
val invertVisibilityMethod =
206-
context.toMethodWalker(method).nextMethod(index - 6, true).getMethod() as MutableMethod
207-
// change visibility of the buttons
208-
invertVisibilityMethod.addInstructions(
209-
0,
210-
"""
211-
invoke-static {p1}, $INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->changeVisibilityNegatedImmediate(Z)V
212-
invoke-static {p1}, $INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->changeVisibilityNegatedImmediate(Z)V
213-
""".trimIndent(),
214-
)
215-
}
216-
}
217-
}
218-
}
174+
// Change visibility of the buttons.
175+
PlayerControlsBytecodePatch.initializeTopControl(INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR)
176+
PlayerControlsBytecodePatch.injectVisibilityCheckCall(INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR)
219177

220-
// change visibility of the buttons
221-
PlayerControlsBytecodePatch.injectVisibilityCheckCall("$INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->changeVisibility(Z)V")
222-
PlayerControlsBytecodePatch.injectVisibilityCheckCall("$INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->changeVisibility(Z)V")
178+
PlayerControlsBytecodePatch.initializeTopControl(INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR)
179+
PlayerControlsBytecodePatch.injectVisibilityCheckCall(INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR)
223180

224-
// append the new time to the player layout
181+
// Append the new time to the player layout.
225182
val appendTimeFingerprintResult = AppendTimeFingerprint.result!!
226183
val appendTimePatternScanStartIndex = appendTimeFingerprintResult.scanResult.patternScanResult!!.startIndex
227184
val targetRegister =
Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
package app.revanced.patches.youtube.layout.sponsorblock
22

33
import app.revanced.patcher.data.ResourceContext
4-
import app.revanced.patcher.patch.PatchException
54
import app.revanced.patcher.patch.ResourcePatch
65
import app.revanced.patcher.patch.annotation.Patch
76
import app.revanced.patches.all.misc.resources.AddResourcesPatch
87
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
98
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
9+
import app.revanced.patches.youtube.misc.playercontrols.PlayerControlsResourcePatch
1010
import app.revanced.patches.youtube.misc.settings.SettingsPatch
1111
import app.revanced.patches.youtube.misc.settings.SettingsResourcePatch
1212
import app.revanced.util.ResourceGroup
1313
import app.revanced.util.copyResources
14-
import app.revanced.util.copyXmlNode
15-
import app.revanced.util.inputStreamFromBundledResource
1614

1715
@Patch(
1816
dependencies = [
@@ -60,49 +58,6 @@ internal object SponsorBlockResourcePatch : ResourcePatch() {
6058
context.copyResources("sponsorblock", resourceGroup)
6159
}
6260

63-
// copy nodes from host resources to their real xml files
64-
65-
val hostingResourceStream =
66-
inputStreamFromBundledResource(
67-
"sponsorblock",
68-
"host/layout/youtube_controls_layout.xml",
69-
)!!
70-
71-
var modifiedControlsLayout = false
72-
val editor = context.xmlEditor["res/layout/youtube_controls_layout.xml"]
73-
"RelativeLayout".copyXmlNode(
74-
context.xmlEditor[hostingResourceStream],
75-
editor,
76-
).also {
77-
val document = editor.file
78-
79-
val children = document.getElementsByTagName("RelativeLayout").item(0).childNodes
80-
81-
// Replace the startOf with the voting button view so that the button does not overlap
82-
for (i in 1 until children.length) {
83-
val view = children.item(i)
84-
85-
// Replace the attribute for a specific node only
86-
if (!(
87-
view.hasAttributes() &&
88-
view.attributes.getNamedItem(
89-
"android:id",
90-
).nodeValue.endsWith("live_chat_overlay_button")
91-
)
92-
) {
93-
continue
94-
}
95-
96-
// voting button id from the voting button view from the youtube_controls_layout.xml host file
97-
val votingButtonId = "@+id/revanced_sb_voting_button"
98-
99-
view.attributes.getNamedItem("android:layout_toStartOf").nodeValue = votingButtonId
100-
101-
modifiedControlsLayout = true
102-
break
103-
}
104-
}.close()
105-
106-
if (!modifiedControlsLayout) throw PatchException("Could not modify controls layout")
61+
PlayerControlsResourcePatch.addTopControls("sponsorblock")
10762
}
10863
}

src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/BottomControlsResourcePatch.kt

Lines changed: 8 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,70 +3,18 @@ package app.revanced.patches.youtube.misc.playercontrols
33
import app.revanced.patcher.data.ResourceContext
44
import app.revanced.patcher.patch.ResourcePatch
55
import app.revanced.patcher.patch.annotation.Patch
6-
import app.revanced.patcher.util.DomFileEditor
7-
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
86
import java.io.Closeable
97

10-
@Patch(dependencies = [ResourceMappingPatch::class])
8+
@Patch(
9+
dependencies = [PlayerControlsBytecodePatch::class],
10+
)
11+
@Deprecated("Patch renamed to PlayerControlsResourcePatch", replaceWith = ReplaceWith("PlayerControlsBytecodePatch"))
1112
object BottomControlsResourcePatch : ResourcePatch(), Closeable {
12-
internal var bottomUiContainerResourceId: Long = -1
13+
override fun execute(context: ResourceContext) {}
1314

14-
private const val TARGET_RESOURCE_NAME = "youtube_controls_bottom_ui_container.xml"
15-
private const val TARGET_RESOURCE = "res/layout/$TARGET_RESOURCE_NAME"
16-
17-
// The element to the left of the element being added.
18-
private var lastLeftOf = "fullscreen_button"
19-
20-
private lateinit var resourceContext: ResourceContext
21-
private lateinit var targetDocumentEditor: DomFileEditor
22-
23-
override fun execute(context: ResourceContext) {
24-
resourceContext = context
25-
targetDocumentEditor = context.xmlEditor[TARGET_RESOURCE]
26-
27-
bottomUiContainerResourceId = ResourceMappingPatch["id", "bottom_ui_container_stub"]
28-
}
29-
30-
/**
31-
* Add new controls to the bottom of the YouTube player.
32-
*
33-
* @param resourceDirectoryName The name of the directory containing the hosting resource.
34-
*/
3515
fun addControls(resourceDirectoryName: String) {
36-
val sourceDocumentEditor = resourceContext.xmlEditor[
37-
this::class.java.classLoader.getResourceAsStream(
38-
"$resourceDirectoryName/host/layout/$TARGET_RESOURCE_NAME",
39-
)!!,
40-
]
41-
val sourceDocument = sourceDocumentEditor.file
42-
val targetDocument = targetDocumentEditor.file
43-
44-
val targetElementTag = "android.support.constraint.ConstraintLayout"
45-
46-
val sourceElements = sourceDocument.getElementsByTagName(targetElementTag).item(0).childNodes
47-
val targetElement = targetDocument.getElementsByTagName(targetElementTag).item(0)
48-
49-
for (index in 1 until sourceElements.length) {
50-
val element = sourceElements.item(index).cloneNode(true)
51-
52-
// If the element has no attributes there's no point to adding it to the destination.
53-
if (!element.hasAttributes()) continue
54-
55-
// Set the elements lastLeftOf attribute to the lastLeftOf value.
56-
val namespace = "@+id"
57-
element.attributes.getNamedItem("yt:layout_constraintRight_toLeftOf").nodeValue =
58-
"$namespace/$lastLeftOf"
59-
60-
// Set lastLeftOf attribute to the current element.
61-
val nameSpaceLength = 5
62-
lastLeftOf = element.attributes.getNamedItem("android:id").nodeValue.substring(nameSpaceLength)
63-
64-
// Add the element.
65-
targetDocument.adoptNode(element)
66-
targetElement.appendChild(element)
67-
}
68-
sourceDocumentEditor.close()
16+
PlayerControlsResourcePatch.addBottomControls(resourceDirectoryName)
6917
}
7018

71-
override fun close() = targetDocumentEditor.close()
72-
}
19+
override fun close() {}
20+
}

0 commit comments

Comments
 (0)