fix(YouTube - Change form factor): Explore button sometimes shows in Automotive layout
Co-authored-by: inotia00 <108592928+inotia00@users.noreply.github.com>
This commit is contained in:
parent
9fa641ed81
commit
733f3bb2cd
12 changed files with 222 additions and 115 deletions
|
|
@ -215,6 +215,7 @@ val hideAdsPatch = bytecodePatch(
|
|||
setOf(
|
||||
Endpoint.BROWSE,
|
||||
Endpoint.SEARCH,
|
||||
Endpoint.NEXT,
|
||||
).forEach { endpoint ->
|
||||
addOSNameHook(
|
||||
endpoint,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,18 @@
|
|||
package app.revanced.patches.youtube.ad.video
|
||||
|
||||
import app.revanced.patcher.gettingFirstMethodDeclaratively
|
||||
import app.revanced.patcher.parameterTypes
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
import app.revanced.patcher.returnType
|
||||
|
||||
internal val BytecodePatchContext.loadVideoAdsMethod by gettingFirstMethodDeclaratively(
|
||||
"TriggerBundle doesn't have the required metadata specified by the trigger ",
|
||||
"Ping migration no associated ping bindings for activated trigger: ",
|
||||
)
|
||||
|
||||
internal val BytecodePatchContext.playerBytesAdLayoutMethod by gettingFirstMethodDeclaratively(
|
||||
"Bootstrapped layout construction resulted in non PlayerBytesLayout. PlayerAds count: "
|
||||
) {
|
||||
returnType("V")
|
||||
parameterTypes("L")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
package app.revanced.patches.youtube.ad.video
|
||||
|
||||
import app.revanced.patcher.extensions.ExternalLabel
|
||||
import app.revanced.patcher.extensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.misc.contexthook.Endpoint
|
||||
import app.revanced.patches.youtube.misc.contexthook.addOSNameHook
|
||||
import app.revanced.patches.youtube.misc.contexthook.hookClientContextPatch
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/patches/VideoAdsPatch;"
|
||||
|
||||
@Suppress("ObjectPropertyName")
|
||||
val videoAdsPatch = bytecodePatch(
|
||||
name = "Video ads",
|
||||
|
|
@ -20,6 +24,7 @@ val videoAdsPatch = bytecodePatch(
|
|||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
hookClientContextPatch
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
|
|
@ -41,15 +46,33 @@ val videoAdsPatch = bytecodePatch(
|
|||
SwitchPreference("revanced_hide_video_ads"),
|
||||
)
|
||||
|
||||
loadVideoAdsMethod.addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
invoke-static { }, Lapp/revanced/extension/youtube/patches/VideoAdsPatch;->shouldShowAds()Z
|
||||
move-result v0
|
||||
if-nez v0, :show_video_ads
|
||||
return-void
|
||||
""",
|
||||
ExternalLabel("show_video_ads", loadVideoAdsMethod.getInstruction(0)),
|
||||
)
|
||||
setOf(
|
||||
loadVideoAdsMethod,
|
||||
playerBytesAdLayoutMethod,
|
||||
).forEach { method ->
|
||||
method.addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideVideoAds()Z
|
||||
move-result v0
|
||||
if-eqz v0, :show_video_ads
|
||||
return-void
|
||||
:show_video_ads
|
||||
nop
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
setOf(
|
||||
Endpoint.GET_WATCH,
|
||||
Endpoint.PLAYER,
|
||||
Endpoint.REEL,
|
||||
).forEach { endpoint ->
|
||||
addOSNameHook(
|
||||
endpoint,
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->hideVideoAds(Ljava/lang/String;)Ljava/lang/String;",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ import app.revanced.patcher.patch.bytecodePatch
|
|||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
||||
import app.revanced.patches.youtube.misc.contexthook.Endpoint
|
||||
import app.revanced.patches.youtube.misc.contexthook.addClientFormFactorHook
|
||||
import app.revanced.patches.youtube.misc.contexthook.hookClientContextPatch
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.navigation.hookNavigationButtonCreated
|
||||
import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch
|
||||
|
|
@ -27,6 +30,7 @@ val changeFormFactorPatch = bytecodePatch(
|
|||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
hookClientContextPatch,
|
||||
navigationBarHookPatch
|
||||
)
|
||||
|
||||
|
|
@ -49,8 +53,6 @@ val changeFormFactorPatch = bytecodePatch(
|
|||
ListPreference("revanced_change_form_factor"),
|
||||
)
|
||||
|
||||
hookNavigationButtonCreated(EXTENSION_CLASS_DESCRIPTOR)
|
||||
|
||||
val formFactorEnumConstructorClass = formFactorEnumConstructorMethod.definingClass
|
||||
|
||||
val createPlayerRequestBodyWithModelMatch = firstMethodComposite {
|
||||
|
|
@ -71,11 +73,23 @@ val changeFormFactorPatch = bytecodePatch(
|
|||
addInstructions(
|
||||
index + 1,
|
||||
"""
|
||||
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getFormFactor(I)I
|
||||
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getUniversalFormFactor(I)I
|
||||
move-result v$register
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
setOf(
|
||||
Endpoint.GET_WATCH,
|
||||
Endpoint.NEXT,
|
||||
Endpoint.GUIDE,
|
||||
Endpoint.REEL,
|
||||
).forEach { endpoint ->
|
||||
addClientFormFactorHook(
|
||||
endpoint,
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->replaceBrokenFormFactor(I)I",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,21 @@
|
|||
package app.revanced.patches.youtube.misc.contexthook
|
||||
|
||||
import app.revanced.com.android.tools.smali.dexlib2.mutable.MutableMethod
|
||||
import app.revanced.com.android.tools.smali.dexlib2.mutable.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.accessFlags
|
||||
import app.revanced.patcher.allOf
|
||||
import app.revanced.patcher.classDef
|
||||
import app.revanced.patcher.composingFirstMethod
|
||||
import app.revanced.patcher.extensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.fieldReference
|
||||
import app.revanced.patcher.extensions.getInstruction
|
||||
import app.revanced.patcher.extensions.methodReference
|
||||
import app.revanced.patcher.field
|
||||
import app.revanced.patcher.firstMethodComposite
|
||||
import app.revanced.patcher.firstMethodDeclaratively
|
||||
import app.revanced.patcher.immutableClassDef
|
||||
import app.revanced.patcher.instructions
|
||||
import app.revanced.patcher.invoke
|
||||
import app.revanced.patcher.method
|
||||
import app.revanced.patcher.parameterTypes
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
|
|
@ -26,8 +32,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
|||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
private lateinit var browseIdField: FieldReference
|
||||
private lateinit var clientFormFactorField: FieldReference
|
||||
private lateinit var clientInfoField: FieldReference
|
||||
private lateinit var clientVersionField: FieldReference
|
||||
private lateinit var messageLiteBuilderField: FieldReference
|
||||
|
|
@ -41,9 +48,15 @@ enum class Endpoint(
|
|||
BROWSE(
|
||||
BytecodePatchContext::browseEndpointParentMethod::get
|
||||
),
|
||||
GET_WATCH(
|
||||
BytecodePatchContext::getWatchEndpointConstructorPrimaryMethod::get,
|
||||
BytecodePatchContext::getWatchEndpointConstructorSecondaryMethod::get,
|
||||
),
|
||||
GUIDE(
|
||||
BytecodePatchContext::guideEndpointConstructorMethod::get
|
||||
),
|
||||
NEXT(BytecodePatchContext::nextEndpointParentMethod::get),
|
||||
PLAYER(BytecodePatchContext::playerEndpointParentMethod::get),
|
||||
REEL(
|
||||
BytecodePatchContext::reelCreateItemsEndpointConstructorMethod::get,
|
||||
BytecodePatchContext::reelItemWatchEndpointConstructorMethod::get,
|
||||
|
|
@ -90,12 +103,8 @@ val hookClientContextPatch = bytecodePatch(
|
|||
}
|
||||
}
|
||||
|
||||
browseEndpointParentMethod.immutableClassDef.browseEndpointConstructorMethodMatch.let {
|
||||
it.method.apply {
|
||||
val browseIdIndex = it[-1]
|
||||
browseIdField =
|
||||
getInstruction<ReferenceInstruction>(browseIdIndex).fieldReference!!
|
||||
}
|
||||
clientFormFactorField = getSetClientFormFactorMethodMatch().let {
|
||||
it.method.getInstruction<ReferenceInstruction>(it[0]).fieldReference!!
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +149,7 @@ val hookClientContextPatch = bytecodePatch(
|
|||
}
|
||||
)
|
||||
|
||||
it.findInstructionIndicesReversedOrThrow(Opcode.RETURN_VOID).forEach { index ->
|
||||
it.findInstructionIndicesReversedOrThrow(Opcode.RETURN_VOID).forEach { index ->
|
||||
it.addInstructionsAtControlFlowLabel(
|
||||
index,
|
||||
"invoke-direct/range { p0 .. p0 }, ${it.definingClass}->$helperMethodName()V"
|
||||
|
|
@ -152,19 +161,22 @@ val hookClientContextPatch = bytecodePatch(
|
|||
}
|
||||
}
|
||||
|
||||
fun addClientFormFactorHook(endPoint: Endpoint, descriptor: String) {
|
||||
endPoint.instructions += """
|
||||
iget v2, v1, $clientFormFactorField
|
||||
invoke-static { v2 }, $descriptor
|
||||
move-result v2
|
||||
iput v2, v1, $clientFormFactorField
|
||||
"""
|
||||
}
|
||||
|
||||
fun addClientVersionHook(endPoint: Endpoint, descriptor: String) {
|
||||
endPoint.instructions += if (endPoint == Endpoint.BROWSE) """
|
||||
iget-object v3, p0, $browseIdField
|
||||
iget-object v2, v1, $clientVersionField
|
||||
invoke-static { v3, v2 }, $descriptor
|
||||
move-result-object v2
|
||||
iput-object v2, v1, $clientVersionField
|
||||
""" else """
|
||||
endPoint.instructions += """
|
||||
iget-object v2, v1, $clientVersionField
|
||||
invoke-static { v2 }, $descriptor
|
||||
move-result-object v2
|
||||
iput-object v2, v1, $clientVersionField
|
||||
"""
|
||||
"""
|
||||
}
|
||||
|
||||
fun addOSNameHook(endPoint: Endpoint, descriptor: String) {
|
||||
|
|
@ -173,5 +185,5 @@ fun addOSNameHook(endPoint: Endpoint, descriptor: String) {
|
|||
invoke-static { v2 }, $descriptor
|
||||
move-result-object v2
|
||||
iput-object v2, v1, $osNameField
|
||||
"""
|
||||
"""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package app.revanced.patches.youtube.misc.contexthook
|
||||
|
||||
import app.revanced.patcher.ClassDefComposing
|
||||
import app.revanced.patcher.CompositeMatch
|
||||
import app.revanced.patcher.accessFlags
|
||||
import app.revanced.patcher.after
|
||||
import app.revanced.patcher.afterAtMost
|
||||
|
|
@ -9,8 +10,11 @@ import app.revanced.patcher.composingFirstMethod
|
|||
import app.revanced.patcher.custom
|
||||
import app.revanced.patcher.extensions.methodReference
|
||||
import app.revanced.patcher.field
|
||||
import app.revanced.patcher.firstImmutableMethodDeclaratively
|
||||
import app.revanced.patcher.firstMethodComposite
|
||||
import app.revanced.patcher.gettingFirstImmutableMethodDeclaratively
|
||||
import app.revanced.patcher.gettingFirstMethodDeclaratively
|
||||
import app.revanced.patcher.immutableClassDef
|
||||
import app.revanced.patcher.instructions
|
||||
import app.revanced.patcher.invoke
|
||||
import app.revanced.patcher.method
|
||||
|
|
@ -22,7 +26,6 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
|||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.google.common.io.ByteArrayDataOutput
|
||||
|
||||
internal const val CLIENT_INFO_CLASS_DESCRIPTOR =
|
||||
$$"Lcom/google/protos/youtube/api/innertube/InnertubeContext$ClientInfo;"
|
||||
|
|
@ -86,25 +89,33 @@ internal val BytecodePatchContext.buildDummyClientContextBodyMethodMatch by comp
|
|||
)
|
||||
}
|
||||
|
||||
internal val ClassDef.browseEndpointConstructorMethodMatch by ClassDefComposing.composingFirstMethod {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
returnType("V")
|
||||
|
||||
var methodDefiningClass = ""
|
||||
custom {
|
||||
methodDefiningClass = this.definingClass
|
||||
true
|
||||
|
||||
|
||||
internal fun BytecodePatchContext.getSetClientFormFactorMethodMatch(): CompositeMatch {
|
||||
val clientFormFactorEnumConstructorMethod = firstImmutableMethodDeclaratively(
|
||||
"UNKNOWN_FORM_FACTOR",
|
||||
"SMALL_FORM_FACTOR",
|
||||
"LARGE_FORM_FACTOR",
|
||||
"AUTOMOTIVE_FORM_FACTOR",
|
||||
"WEARABLE_FORM_FACTOR",
|
||||
) {
|
||||
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
|
||||
}.immutableClassDef.firstMethodComposite {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
||||
returnType("L")
|
||||
parameterTypes("I")
|
||||
}
|
||||
|
||||
instructions(
|
||||
""(),
|
||||
after(
|
||||
allOf(
|
||||
Opcode.IPUT_OBJECT(),
|
||||
field { definingClass == methodDefiningClass && type == "Ljava/lang/String;" }
|
||||
)
|
||||
),
|
||||
)
|
||||
return firstMethodComposite {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returnType("V")
|
||||
parameterTypes("L")
|
||||
instructions(
|
||||
allOf(Opcode.IGET(), field { type == "I" && definingClass == CLIENT_INFO_CLASS_DESCRIPTOR }),
|
||||
method { this == clientFormFactorEnumConstructorMethod }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal val BytecodePatchContext.browseEndpointParentMethod by gettingFirstImmutableMethodDeclaratively(
|
||||
|
|
@ -113,6 +124,22 @@ internal val BytecodePatchContext.browseEndpointParentMethod by gettingFirstImmu
|
|||
returnType("Ljava/lang/String;")
|
||||
}
|
||||
|
||||
internal val BytecodePatchContext.getWatchEndpointConstructorPrimaryMethod by gettingFirstMethodDeclaratively(
|
||||
"get_watch"
|
||||
) {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
returnType("V")
|
||||
custom { immutableClassDef.fields.any { it.type == "Ljava/util/function/Consumer;" } }
|
||||
}
|
||||
|
||||
internal val BytecodePatchContext.getWatchEndpointConstructorSecondaryMethod by gettingFirstMethodDeclaratively(
|
||||
"get_watch"
|
||||
) {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
returnType("V")
|
||||
custom { immutableClassDef.fields.none { it.type == "Ljava/util/function/Consumer;" } }
|
||||
}
|
||||
|
||||
internal val BytecodePatchContext.guideEndpointConstructorMethod by gettingFirstImmutableMethodDeclaratively(
|
||||
"guide"
|
||||
) {
|
||||
|
|
@ -120,6 +147,18 @@ internal val BytecodePatchContext.guideEndpointConstructorMethod by gettingFirst
|
|||
returnType("V")
|
||||
}
|
||||
|
||||
internal val BytecodePatchContext.nextEndpointParentMethod by gettingFirstImmutableMethodDeclaratively(
|
||||
"watchNextType"
|
||||
) {
|
||||
returnType("Ljava/lang/String;")
|
||||
}
|
||||
|
||||
internal val BytecodePatchContext.playerEndpointParentMethod by gettingFirstImmutableMethodDeclaratively(
|
||||
"dataExpiredForSeconds"
|
||||
) {
|
||||
returnType("Ljava/lang/String;")
|
||||
}
|
||||
|
||||
internal val BytecodePatchContext.reelCreateItemsEndpointConstructorMethod by gettingFirstImmutableMethodDeclaratively(
|
||||
"reel/create_reel_items"
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -1428,10 +1428,16 @@ Ready to submit?"</string>
|
|||
|
||||
Tablet layout
|
||||
• Community posts are hidden
|
||||
• Playback in feeds setting is not available
|
||||
• Remix button and Sound button are not available in Shorts
|
||||
• Video action bar is not collapsed
|
||||
|
||||
Automotive layout
|
||||
• Feed is organized by topics and channels
|
||||
• Playback in feeds setting is not available
|
||||
• Remix button and Sound button are not available in Shorts
|
||||
• Shorts open in the regular player
|
||||
• Feed is organized by topics and channels"</string>
|
||||
• Video action bar is not collapsed"</string>
|
||||
</patch>
|
||||
<patch id="layout.spoofappversion.spoofAppVersionPatch">
|
||||
<string name="revanced_spoof_app_version_title">Spoof app version</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue