feat(YouTube): add Spoof format stream data patch 8ecbef66ee

This commit is contained in:
inotia00 2024-05-09 00:51:39 +09:00
parent b5d699c5f4
commit 215a709b13
5 changed files with 178 additions and 1 deletions

View File

@ -0,0 +1,123 @@
package app.revanced.patches.youtube.utils.fix.formatstream
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.patch.PatchException
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.utils.compatibility.Constants
import app.revanced.patches.youtube.utils.fix.formatstream.fingerprints.FormatStreamModelConstructorFingerprint
import app.revanced.patches.youtube.utils.fix.formatstream.fingerprints.VideoStreamingDataConstructorFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.MISC_PATH
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.patches.youtube.video.information.VideoInformationPatch
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.addFieldAndInstructions
import app.revanced.util.getTargetIndex
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@Suppress("unused")
object SpoofFormatStreamDataPatch : BaseBytecodePatch(
name = "Spoof format stream data",
description = "Adds options to spoof format stream data to prevent playback issues.",
dependencies = setOf(
PlayerResponseMethodHookPatch::class,
SettingsPatch::class,
VideoIdPatch::class,
VideoInformationPatch::class,
),
compatiblePackages = Constants.COMPATIBLE_PACKAGE,
fingerprints = setOf(
FormatStreamModelConstructorFingerprint,
VideoStreamingDataConstructorFingerprint
)
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"$MISC_PATH/SpoofFormatStreamDataPatch;"
override fun execute(context: BytecodeContext) {
// hook player response video id, to start loading format stream data sooner in the background.
VideoIdPatch.hookPlayerResponseVideoId("$INTEGRATIONS_CLASS_DESCRIPTOR->newPlayerResponseVideoId(Ljava/lang/String;Z)V")
// TODO: Check if all instructions need to be spoofed.
FormatStreamModelConstructorFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val formatStreamDataIndex = it.scanResult.patternScanResult!!.startIndex
val formatStreamDataReference = getInstruction<ReferenceInstruction>(formatStreamDataIndex).reference
val formatStreamDataClass = context.findClass((formatStreamDataReference as FieldReference).definingClass)!!.mutableClass
formatStreamDataClass.methods.find { method -> method.name == "<init>" }
?.apply {
val getSmaliInstructions =
"""
if-eqz v0, :ignore
iget-object v0, v0, $formatStreamDataReference
if-eqz v0, :ignore
return-object v0
:ignore
const-string v0, ""
return-object v0
"""
val setSmaliInstructions =
"""
if-eqz p0, :ignore
if-eqz v0, :ignore
iput-object p0, v0, $formatStreamDataReference
:ignore
return-void
"""
val integrationMutableClass =
context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)!!.mutableClass
integrationMutableClass.addFieldAndInstructions(
context,
"getFormatStreamData",
"formatStreamDataClass",
definingClass,
getSmaliInstructions,
true
)
integrationMutableClass.addFieldAndInstructions(
context,
"setFormatStreamData",
"formatStreamDataClass",
definingClass,
setSmaliInstructions,
true
)
} ?: throw PatchException("FormatStreamDataClass not found!")
hook()
}
}
VideoStreamingDataConstructorFingerprint.resultOrThrow().mutableMethod.hook()
/**
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE_CATEGORY: MISC_EXPERIMENTAL_FLAGS",
"SETTINGS: SPOOF_FORMAT_STREAM_DATA"
)
)
SettingsPatch.updatePatchStatus(this)
}
private fun MutableMethod.hook() =
addInstruction(
1,
"invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->hookFormatStreamData()V"
)
}

View File

@ -0,0 +1,30 @@
package app.revanced.patches.youtube.utils.fix.formatstream.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.utils.fix.formatstream.fingerprints.FormatStreamModelConstructorFingerprint.indexOfParseInstruction
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal object FormatStreamModelConstructorFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
returnType = "V",
opcodes = listOf(
Opcode.IGET_OBJECT, // get formatStreamData
Opcode.INVOKE_STATIC // Uri.parse(String formatStreamData)
),
customFingerprint = { methodDef, classDef ->
classDef.type == "Lcom/google/android/libraries/youtube/innertube/model/media/FormatStreamModel;" &&
indexOfParseInstruction(methodDef) >= 0
}
) {
fun indexOfParseInstruction(methodDef: Method) =
methodDef.indexOfFirstInstruction {
opcode == Opcode.INVOKE_STATIC && getReference<MethodReference>()?.name == "parse"
}
}

View File

@ -0,0 +1,14 @@
package app.revanced.patches.youtube.utils.fix.formatstream.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object VideoStreamingDataConstructorFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
returnType = "V",
customFingerprint = { _, classDef ->
classDef.type == "Lcom/google/android/libraries/youtube/innertube/model/media/VideoStreamingData;"
}
)

View File

@ -1366,6 +1366,13 @@ Tap on the continue button and disable battery optimizations."</string>
<string name="revanced_sanitize_sharing_links_summary">Removes tracking query parameters from the URLs when sharing links.</string>
<string name="revanced_disable_quic_protocol_title">Disable QUIC protocol</string>
<string name="revanced_disable_quic_protocol_summary">"Disable CronetEngine's QUIC protocol."</string>
<string name="revanced_spoof_format_stream_data_title">Spoof format stream data</string>
<string name="revanced_spoof_format_stream_data_summary">"Spoofs format stream data to prevent playback issues.
Limitations:
• There may be about 5 seconds of buffering when the video starts.
• If buffering takes too long, you may need to close and reopen the video.
• Since it is still under development, there may be other unknown issues."</string>
<string name="revanced_spoof_player_parameter_title">Spoof player parameter</string>
<string name="revanced_spoof_player_parameter_summary">"Spoofs player parameters to prevent playback issues.

View File

@ -551,6 +551,9 @@
<!-- PREFERENCE_CATEGORY: MISC_EXPERIMENTAL_FLAGS
<PreferenceCategory android:title="@string/revanced_preference_category_experimental_flag" android:layout="@layout/revanced_settings_preferences_category"/>PREFERENCE_CATEGORY: MISC_EXPERIMENTAL_FLAGS -->
<!-- SETTINGS: SPOOF_FORMAT_STREAM_DATA
<SwitchPreference android:title="@string/revanced_spoof_format_stream_data_title" android:key="revanced_spoof_format_stream_data" android:defaultValue="false" android:summary="@string/revanced_spoof_format_stream_data_summary" />SETTINGS: SPOOF_FORMAT_STREAM_DATA -->
<!-- SETTINGS: SPOOF_PLAYER_PARAMETER
<SwitchPreference android:title="@string/revanced_spoof_player_parameter_title" android:key="revanced_spoof_player_parameter" android:defaultValue="false" android:summary="@string/revanced_spoof_player_parameter_summary" />
<SwitchPreference android:title="@string/revanced_spoof_player_parameter_in_feed_title" android:key="revanced_spoof_player_parameter_in_feed" android:defaultValue="false" android:summaryOn="@string/revanced_spoof_player_parameter_in_feed_summary_on" android:summaryOff="@string/revanced_spoof_player_parameter_in_feed_summary_off" android:dependency="revanced_spoof_player_parameter" />SETTINGS: SPOOF_PLAYER_PARAMETER -->
@ -626,7 +629,7 @@
<Preference android:title="Enable minimized playback" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
<Preference android:title="Enable open links directly" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
<Preference android:title="Sanitize sharing links" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
<Preference android:title="Spoof player parameters" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
<Preference android:title="Spoof format stream data" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/revanced_preference_category_others" android:layout="@layout/revanced_settings_preferences_category">