Skip to content

Commit 6d4af87

Browse files
utafraliinotia00
andauthored
fix(YouTube - Hide end screen suggested video): Add user dialogs to minimize user confusion (#637)
Co-authored-by: inotia00 <108592928+inotia00@users.noreply.github.com>
1 parent 8d86a56 commit 6d4af87

4 files changed

Lines changed: 70 additions & 53 deletions

File tree

extensions/youtube/src/main/java/app/morphe/extension/youtube/settings/Settings.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ public class Settings extends SharedYouTubeSettings {
177177
public static final BooleanSetting HIDE_CROWDFUNDING_BOX = new BooleanSetting("morphe_hide_crowdfunding_box", FALSE, true);
178178
public static final BooleanSetting HIDE_EMERGENCY_BOX = new BooleanSetting("morphe_hide_emergency_box", TRUE);
179179
public static final BooleanSetting HIDE_END_SCREEN_CARDS = new BooleanSetting("morphe_hide_end_screen_cards", FALSE);
180-
public static final BooleanSetting HIDE_END_SCREEN_SUGGESTED_VIDEO = new BooleanSetting("morphe_end_screen_suggested_video", FALSE, true);
180+
public static final BooleanSetting HIDE_END_SCREEN_SUGGESTED_VIDEO = new BooleanSetting("morphe_end_screen_suggested_video", FALSE, true,
181+
"morphe_end_screen_suggested_video_user_dialog_message");
181182
public static final BooleanSetting HIDE_FULLSCREEN_BUTTON = new BooleanSetting("morphe_hide_fullscreen_button", FALSE, true);
182183
public static final BooleanSetting HIDE_INFO_CARDS = new BooleanSetting("morphe_hide_info_cards", FALSE);
183184
public static final BooleanSetting HIDE_INFO_PANELS = new BooleanSetting("morphe_hide_info_panels", TRUE);
Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package app.morphe.patches.youtube.layout.hide.endscreensuggestedvideo
22

33
import app.morphe.patcher.Fingerprint
4-
import app.morphe.patcher.OpcodesFilter
5-
import app.morphe.util.getReference
6-
import app.morphe.util.indexOfFirstInstruction
4+
import app.morphe.patcher.InstructionLocation.MatchAfterWithin
5+
import app.morphe.patcher.fieldAccess
6+
import app.morphe.patcher.methodCall
77
import com.android.tools.smali.dexlib2.AccessFlags
88
import com.android.tools.smali.dexlib2.Opcode
9-
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
109

1110
internal object AutoNavConstructorFingerprint : Fingerprint(
1211
returnType = "V",
@@ -24,17 +23,22 @@ internal object RemoveOnLayoutChangeListenerFingerprint : Fingerprint(
2423
accessFlags = listOf(AccessFlags.PUBLIC, AccessFlags.FINAL),
2524
returnType = "V",
2625
parameters = listOf(),
27-
filters = OpcodesFilter.opcodesToFilters(
28-
Opcode.IPUT,
29-
Opcode.INVOKE_VIRTUAL
30-
),
31-
// This is the only reference present in the entire smali.,
32-
custom = { method, _ ->
33-
// TODO: Convert this to an instruction filter
34-
method.indexOfFirstInstruction {
35-
val reference = getReference<MethodReference>()
36-
reference?.name == "removeOnLayoutChangeListener" &&
37-
reference.definingClass.endsWith("/YouTubePlayerOverlaysLayout;")
38-
} >= 0
39-
}
26+
filters = listOf(
27+
fieldAccess(
28+
opcode = Opcode.IPUT,
29+
type = "I"
30+
),
31+
methodCall(
32+
opcode = Opcode.INVOKE_VIRTUAL,
33+
parameters = listOf(),
34+
returnType = "V",
35+
location = MatchAfterWithin(3)
36+
),
37+
methodCall(
38+
opcode = Opcode.INVOKE_VIRTUAL,
39+
definingClass = "Lcom/google/android/apps/youtube/app/common/player/overlay/YouTubePlayerOverlaysLayout;",
40+
name = "removeOnLayoutChangeListener",
41+
returnType = "V"
42+
)
43+
)
4044
)

patches/src/main/kotlin/app/morphe/patches/youtube/layout/hide/endscreensuggestedvideo/HideEndScreenSuggestedVideoPatch.kt

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
package app.morphe.patches.youtube.layout.hide.endscreensuggestedvideo
22

3+
import app.morphe.patcher.Fingerprint
4+
import app.morphe.patcher.InstructionLocation.MatchAfterWithin
35
import app.morphe.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
4-
import app.morphe.patcher.extensions.InstructionExtensions.getInstruction
6+
import app.morphe.patcher.fieldAccess
7+
import app.morphe.patcher.methodCall
58
import app.morphe.patcher.patch.bytecodePatch
6-
import app.morphe.patcher.util.smali.ExternalLabel
79
import app.morphe.patches.shared.misc.settings.preference.SwitchPreference
810
import app.morphe.patches.youtube.misc.extension.sharedExtensionPatch
911
import app.morphe.patches.youtube.misc.settings.PreferenceScreen
1012
import app.morphe.patches.youtube.shared.Constants.COMPATIBILITY_YOUTUBE
1113
import app.morphe.util.getMutableMethod
1214
import app.morphe.util.getReference
13-
import app.morphe.util.indexOfFirstInstructionOrThrow
14-
import app.morphe.util.indexOfFirstInstructionReversedOrThrow
15+
import com.android.tools.smali.dexlib2.AccessFlags
1516
import com.android.tools.smali.dexlib2.Opcode
16-
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
17+
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
1718
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
1819

1920
private const val EXTENSION_CLASS_DESCRIPTOR =
@@ -24,9 +25,7 @@ val hideEndScreenSuggestedVideoPatch = bytecodePatch(
2425
name = "Hide end screen suggested video",
2526
description = "Adds an option to hide the suggested video at the end of videos.",
2627
) {
27-
dependsOn(
28-
sharedExtensionPatch,
29-
)
28+
dependsOn(sharedExtensionPatch)
3029

3130
compatibleWith(COMPATIBILITY_YOUTUBE)
3231

@@ -35,44 +34,56 @@ val hideEndScreenSuggestedVideoPatch = bytecodePatch(
3534
SwitchPreference("morphe_end_screen_suggested_video"),
3635
)
3736

38-
RemoveOnLayoutChangeListenerFingerprint.let {
39-
val endScreenMethod = it.instructionMatches.last().getInstruction<ReferenceInstruction>()
40-
.getReference<MethodReference>()!!.getMutableMethod()
37+
val autoNavStatusMethod = AutoNavStatusFingerprint.match(
38+
AutoNavConstructorFingerprint.originalClassDef
39+
).method
4140

42-
endScreenMethod.apply {
43-
val autoNavStatusMethodName = AutoNavStatusFingerprint.match(
44-
AutoNavConstructorFingerprint.classDef
45-
).originalMethod.name
41+
val endScreenMethod = RemoveOnLayoutChangeListenerFingerprint.instructionMatches[1]
42+
.instruction.getReference<MethodReference>()!!.getMutableMethod()
4643

47-
val invokeIndex = indexOfFirstInstructionOrThrow {
48-
val reference = getReference<MethodReference>()
49-
reference?.name == autoNavStatusMethodName &&
50-
reference.returnType == "Z" &&
51-
reference.parameterTypes.isEmpty()
52-
}
53-
val iGetObjectIndex = indexOfFirstInstructionReversedOrThrow(invokeIndex, Opcode.IGET_OBJECT)
54-
val invokeReference = getInstruction<ReferenceInstruction>(invokeIndex).reference
55-
val iGetObjectReference = getInstruction<ReferenceInstruction>(iGetObjectIndex).reference
56-
val opcodeName = getInstruction(invokeIndex).opcode.name
44+
val endScreenSuggestedVideoFingerprint = Fingerprint(
45+
definingClass = endScreenMethod.definingClass,
46+
name = endScreenMethod.name,
47+
accessFlags = listOf(AccessFlags.PUBLIC, AccessFlags.FINAL),
48+
returnType = "V",
49+
parameters = listOf(),
50+
filters = listOf(
51+
fieldAccess(
52+
opcode = Opcode.IGET_OBJECT,
53+
definingClass = "this",
54+
type = autoNavStatusMethod.definingClass
55+
),
56+
methodCall(
57+
opcode = Opcode.INVOKE_VIRTUAL,
58+
smali = autoNavStatusMethod.toString(),
59+
location = MatchAfterWithin(3)
60+
)
61+
)
62+
)
63+
64+
endScreenSuggestedVideoFingerprint.let {
65+
it.method.apply {
66+
val autoNavField = it.instructionMatches.first().instruction.getReference<FieldReference>()!!
5767

5868
addInstructionsWithLabels(
5969
0,
6070
"""
6171
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->hideEndScreenSuggestedVideo()Z
6272
move-result v0
63-
if-eqz v0, :show_end_screen_recommendation
73+
if-eqz v0, :ignore
6474
65-
iget-object v0, p0, $iGetObjectReference
75+
iget-object v0, p0, $autoNavField
6676
6777
# This reference checks whether autoplay is turned on.
68-
$opcodeName { v0 }, $invokeReference
78+
invoke-virtual { v0 }, $autoNavStatusMethod
6979
move-result v0
7080
7181
# Hide suggested video end screen only when autoplay is turned off.
72-
if-nez v0, :show_end_screen_recommendation
82+
if-nez v0, :ignore
7383
return-void
74-
""",
75-
ExternalLabel("show_end_screen_recommendation", getInstruction(0))
84+
:ignore
85+
nop
86+
"""
7687
)
7788
}
7889
}

patches/src/main/resources/addresources/values/youtube/strings.xml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -997,11 +997,12 @@ To show the Audio track menu, change \'Spoof video streams\' to \'Android Reel\'
997997

998998
<!-- layout.hide.endscreensuggestedvideo.hideEndScreenSuggestedVideoPatch -->
999999
<string name="morphe_end_screen_suggested_video_title">Hide end screen suggested video</string>
1000-
<string name="morphe_end_screen_suggested_video_summary_on">"End screen suggested video is hidden when autoplay is turned off
1001-
1002-
Autoplay can be changed in YouTube settings:
1003-
Settings → Playback → Autoplay next video"</string>
1000+
<string name="morphe_end_screen_suggested_video_summary_on">End screen suggested video is hidden when autoplay is turned off</string>
10041001
<string name="morphe_end_screen_suggested_video_summary_off">End screen suggested video is shown</string>
1002+
<string name="morphe_end_screen_suggested_video_user_dialog_message">"This setting only works if 'Autoplay next video' is turned off.
1003+
1004+
'Autoplay next video' can be changed in YouTube settings:
1005+
Settings → Playback (or Autoplay) → Autoplay next video"</string>
10051006

10061007
<!-- layout.hide.relatedvideooverlay.hideRelatedVideoOverlayPatch -->
10071008
<string name="morphe_hide_related_videos_overlay_title">Hide related videos overlay</string>

0 commit comments

Comments
 (0)