mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-30 05:40:19 +02:00
feat(YouTube): remove Spoof format stream data
patch
This commit is contained in:
parent
60c05cb193
commit
65bb867bd2
@ -1,234 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.utils.fix.formatstream
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.patch.PatchException
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
|
||||||
import app.revanced.patches.youtube.utils.compatibility.Constants
|
|
||||||
import app.revanced.patches.youtube.utils.fix.formatstream.fingerprints.EndpointUrlBuilderFingerprint
|
|
||||||
import app.revanced.patches.youtube.utils.fix.formatstream.fingerprints.FormatStreamModelConstructorFingerprint
|
|
||||||
import app.revanced.patches.youtube.utils.fix.formatstream.fingerprints.PlaybackStartConstructorFingerprint
|
|
||||||
import app.revanced.patches.youtube.utils.fix.formatstream.fingerprints.PlaybackStartParentFingerprint
|
|
||||||
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.util.getReference
|
|
||||||
import app.revanced.util.getStringInstructionIndex
|
|
||||||
import app.revanced.util.getTargetIndex
|
|
||||||
import app.revanced.util.getWalkerMethod
|
|
||||||
import app.revanced.util.indexOfFirstInstruction
|
|
||||||
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.OneRegisterInstruction
|
|
||||||
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
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.Reference
|
|
||||||
|
|
||||||
@Suppress("unused")
|
|
||||||
object SpoofFormatStreamDataPatch : BaseBytecodePatch(
|
|
||||||
name = "Spoof format stream data",
|
|
||||||
description = "Adds an option to spoof the format stream data to prevent playback issues.",
|
|
||||||
dependencies = setOf(
|
|
||||||
SettingsPatch::class,
|
|
||||||
VideoInformationPatch::class,
|
|
||||||
),
|
|
||||||
compatiblePackages = Constants.COMPATIBLE_PACKAGE,
|
|
||||||
fingerprints = setOf(
|
|
||||||
EndpointUrlBuilderFingerprint,
|
|
||||||
FormatStreamModelConstructorFingerprint,
|
|
||||||
PlaybackStartParentFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
|
||||||
"$MISC_PATH/SpoofFormatStreamDataPatch;"
|
|
||||||
|
|
||||||
private const val INTEGRATIONS_METHOD_DESCRIPTOR =
|
|
||||||
"hookStreamData"
|
|
||||||
|
|
||||||
private const val INTEGRATIONS_METHOD_CALL =
|
|
||||||
INTEGRATIONS_CLASS_DESCRIPTOR +
|
|
||||||
"->" +
|
|
||||||
INTEGRATIONS_METHOD_DESCRIPTOR +
|
|
||||||
"(Ljava/lang/Object;)V"
|
|
||||||
|
|
||||||
private const val STREAMING_DATA_OUTER_CLASS =
|
|
||||||
"Lcom/google/protos/youtube/api/innertube/StreamingDataOuterClass\$StreamingData;"
|
|
||||||
|
|
||||||
private lateinit var hookMethod: MutableMethod
|
|
||||||
private lateinit var uriMethod: MutableMethod
|
|
||||||
|
|
||||||
private fun MutableMethod.replaceFieldName(
|
|
||||||
index: Int,
|
|
||||||
replaceFieldString: String
|
|
||||||
) {
|
|
||||||
val reference = getInstruction<ReferenceInstruction>(index).reference
|
|
||||||
val fieldName = (reference as FieldReference).name
|
|
||||||
|
|
||||||
hookMethod.apply {
|
|
||||||
val stringIndex = getStringInstructionIndex(replaceFieldString)
|
|
||||||
val stringRegister = getInstruction<OneRegisterInstruction>(stringIndex).registerA
|
|
||||||
|
|
||||||
replaceInstruction(
|
|
||||||
stringIndex,
|
|
||||||
"const-string v$stringRegister, \"$fieldName\""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
|
||||||
|
|
||||||
// region set field name
|
|
||||||
|
|
||||||
hookMethod = context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)!!
|
|
||||||
.mutableClass.methods.find { method -> method.name == INTEGRATIONS_METHOD_DESCRIPTOR }
|
|
||||||
?: throw PatchException("SpoofFormatStreamDataPatch not found")
|
|
||||||
|
|
||||||
FormatStreamModelConstructorFingerprint.resultOrThrow().let {
|
|
||||||
it.mutableMethod.apply {
|
|
||||||
// Find the field name that will be used for reflection.
|
|
||||||
val urlIndex = it.scanResult.patternScanResult!!.startIndex
|
|
||||||
val itagIndex = getTargetIndex(urlIndex + 1, Opcode.IGET)
|
|
||||||
|
|
||||||
replaceFieldName(urlIndex, "replaceMeWithUrlFieldName")
|
|
||||||
replaceFieldName(itagIndex, "replaceMeWithITagFieldName")
|
|
||||||
}
|
|
||||||
|
|
||||||
it.mutableClass.methods.find { method ->
|
|
||||||
method.parameters == listOf("Ljava/lang/String;")
|
|
||||||
&& method.returnType == "Landroid/net/Uri;"
|
|
||||||
}?.apply {
|
|
||||||
val walkerIndex = indexOfFirstInstruction {
|
|
||||||
opcode == Opcode.INVOKE_VIRTUAL
|
|
||||||
&& getReference<MethodReference>()?.returnType == "Landroid/net/Uri;"
|
|
||||||
}
|
|
||||||
uriMethod = getWalkerMethod(context, walkerIndex)
|
|
||||||
} ?: throw PatchException("Uri method not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region set protobufList reference
|
|
||||||
|
|
||||||
lateinit var nonDashProtobufListReference: Reference
|
|
||||||
lateinit var dashProtobufListReference: Reference
|
|
||||||
|
|
||||||
val streamingDataOutClassConstructorMethod = context.findClass(STREAMING_DATA_OUTER_CLASS)!!
|
|
||||||
.mutableClass.methods.find { method -> method.name == "<init>" }
|
|
||||||
?: throw PatchException("StreamingDataOutClass not found")
|
|
||||||
|
|
||||||
streamingDataOutClassConstructorMethod.apply {
|
|
||||||
val protobufListIndex = indexOfFirstInstruction {
|
|
||||||
opcode == Opcode.INVOKE_STATIC
|
|
||||||
&& getReference<MethodReference>()?.definingClass == STREAMING_DATA_OUTER_CLASS
|
|
||||||
&& getReference<MethodReference>()?.name == "emptyProtobufList"
|
|
||||||
}
|
|
||||||
if (protobufListIndex <= 0)
|
|
||||||
throw PatchException("ProtobufList index not found")
|
|
||||||
|
|
||||||
val protobufListReference = getInstruction<ReferenceInstruction>(protobufListIndex).reference
|
|
||||||
val protobufListClass = (protobufListReference as MethodReference).returnType
|
|
||||||
|
|
||||||
val protobufListCalls = implementation!!.instructions.withIndex()
|
|
||||||
.filter { instruction ->
|
|
||||||
((instruction.value as? ReferenceInstruction)?.reference as? FieldReference)?.type == protobufListClass
|
|
||||||
}
|
|
||||||
|
|
||||||
nonDashProtobufListReference =
|
|
||||||
getInstruction<ReferenceInstruction>(protobufListCalls.elementAt(0).index).reference
|
|
||||||
dashProtobufListReference =
|
|
||||||
getInstruction<ReferenceInstruction>(protobufListCalls.elementAt(1).index).reference
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region hook stream data
|
|
||||||
|
|
||||||
PlaybackStartConstructorFingerprint.resolve(
|
|
||||||
context,
|
|
||||||
PlaybackStartParentFingerprint.resultOrThrow().classDef
|
|
||||||
)
|
|
||||||
PlaybackStartConstructorFingerprint.resultOrThrow().let {
|
|
||||||
it.mutableMethod.apply {
|
|
||||||
val streamingDataOuterClassIndex = it.scanResult.patternScanResult!!.startIndex + 1
|
|
||||||
val streamingDataOuterClassReference = getInstruction<ReferenceInstruction>(streamingDataOuterClassIndex).reference
|
|
||||||
if (!streamingDataOuterClassReference.toString().endsWith(STREAMING_DATA_OUTER_CLASS))
|
|
||||||
throw PatchException("Type does not match: $streamingDataOuterClassReference")
|
|
||||||
|
|
||||||
val insertIndex = streamingDataOuterClassIndex + 1
|
|
||||||
val streamingDataOuterClassRegister = getInstruction<TwoRegisterInstruction>(streamingDataOuterClassIndex).registerA
|
|
||||||
val freeRegister = implementation!!.registerCount - parameters.size - 2
|
|
||||||
|
|
||||||
addInstructionsWithLabels(
|
|
||||||
insertIndex,
|
|
||||||
"""
|
|
||||||
if-eqz v$streamingDataOuterClassRegister, :ignore
|
|
||||||
iget-object v$freeRegister, v$streamingDataOuterClassRegister, $nonDashProtobufListReference
|
|
||||||
invoke-static { v$freeRegister }, $INTEGRATIONS_METHOD_CALL
|
|
||||||
iget-object v$freeRegister, v$streamingDataOuterClassRegister, $dashProtobufListReference
|
|
||||||
invoke-static { v$freeRegister }, $INTEGRATIONS_METHOD_CALL
|
|
||||||
""", ExternalLabel("ignore", getInstruction(insertIndex))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uriMethod.apply {
|
|
||||||
val insertIndex = implementation!!.instructions.size - 1
|
|
||||||
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
|
||||||
|
|
||||||
addInstructions(
|
|
||||||
insertIndex, """
|
|
||||||
invoke-static { v$insertRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->hookUri(Landroid/net/Uri;)Landroid/net/Uri;
|
|
||||||
move-result-object v$insertRegister
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region hook endpoint url
|
|
||||||
|
|
||||||
EndpointUrlBuilderFingerprint.resultOrThrow().let {
|
|
||||||
it.mutableMethod.apply {
|
|
||||||
val uriIndex = indexOfFirstInstruction {
|
|
||||||
opcode == Opcode.INVOKE_VIRTUAL
|
|
||||||
&& getReference<MethodReference>()?.definingClass == "Landroid/net/Uri;"
|
|
||||||
&& getReference<MethodReference>()?.name == "toString"
|
|
||||||
}
|
|
||||||
val uriStringIndex = getTargetIndex(uriIndex, Opcode.IPUT_OBJECT)
|
|
||||||
val uriStringReference = getInstruction<ReferenceInstruction>(uriStringIndex).reference
|
|
||||||
|
|
||||||
it.mutableClass.methods.find { method ->
|
|
||||||
method.parameters == listOf("Lcom/google/protobuf/MessageLite;")
|
|
||||||
&& method.returnType == "V"
|
|
||||||
}?.addInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
iget-object v0, p0, $uriStringReference
|
|
||||||
invoke-static { v0 }, $INTEGRATIONS_CLASS_DESCRIPTOR->newEndpointUrlResponse(Ljava/lang/String;)V
|
|
||||||
"""
|
|
||||||
) ?: throw PatchException("PlaybackStart method not found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add settings
|
|
||||||
*/
|
|
||||||
SettingsPatch.addPreference(
|
|
||||||
arrayOf(
|
|
||||||
"PREFERENCE_CATEGORY: MISC_EXPERIMENTAL_FLAGS",
|
|
||||||
"SETTINGS: SPOOF_FORMAT_STREAM_DATA"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
SettingsPatch.updatePatchStatus(this)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
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.EndpointUrlBuilderFingerprint.indexOfToStringInstruction
|
|
||||||
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 EndpointUrlBuilderFingerprint : MethodFingerprint(
|
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.DECLARED_SYNCHRONIZED,
|
|
||||||
returnType = "Ljava/lang/String;",
|
|
||||||
parameters = emptyList(),
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.INVOKE_VIRTUAL, // Uri.toString()
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
),
|
|
||||||
strings = listOf("asig"),
|
|
||||||
customFingerprint = { methodDef, _ ->
|
|
||||||
indexOfToStringInstruction(methodDef) >= 0
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
fun indexOfToStringInstruction(methodDef: Method) =
|
|
||||||
methodDef.indexOfFirstInstruction {
|
|
||||||
opcode == Opcode.INVOKE_VIRTUAL
|
|
||||||
&& getReference<MethodReference>()?.definingClass == "Landroid/net/Uri;"
|
|
||||||
&& getReference<MethodReference>()?.name == "toString"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
|||||||
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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
|||||||
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
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
|
||||||
|
|
||||||
internal object PlaybackStartConstructorFingerprint : MethodFingerprint(
|
|
||||||
returnType = "V",
|
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
|
||||||
parameters = listOf("L"),
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.IPUT,
|
|
||||||
Opcode.IGET_OBJECT, // type: Lcom/google/protos/youtube/api/innertube/StreamingDataOuterClass$StreamingData;
|
|
||||||
Opcode.IF_NEZ
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
|||||||
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 PlaybackStartParentFingerprint : MethodFingerprint(
|
|
||||||
returnType = "Lcom/google/android/libraries/youtube/innertube/model/media/VideoStreamingData;",
|
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
|
||||||
parameters = emptyList(),
|
|
||||||
strings = listOf("Invalid playback type; streaming data is not playable"),
|
|
||||||
)
|
|
||||||
|
|
@ -1396,13 +1396,6 @@ 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_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_title">Disable QUIC protocol</string>
|
||||||
<string name="revanced_disable_quic_protocol_summary">"Disable CronetEngine's 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 the format stream data to prevent playback issues.
|
|
||||||
|
|
||||||
Limitations:
|
|
||||||
• There may be about 5 seconds of buffering when videos start.
|
|
||||||
• If buffering takes too long, you may need to close and reopen the video.
|
|
||||||
• Since this 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_title">Spoof player parameter</string>
|
||||||
<string name="revanced_spoof_player_parameter_summary">"Spoofs player parameters to prevent playback issues.
|
<string name="revanced_spoof_player_parameter_summary">"Spoofs player parameters to prevent playback issues.
|
||||||
|
|
||||||
|
@ -562,9 +562,6 @@
|
|||||||
<!-- PREFERENCE_CATEGORY: MISC_EXPERIMENTAL_FLAGS
|
<!-- 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 -->
|
<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
|
<!-- 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_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 -->
|
<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 -->
|
||||||
@ -644,7 +641,6 @@
|
|||||||
<Preference android:title="Enable minimized playback" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
|
<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="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="Sanitize sharing links" 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"/>
|
|
||||||
<Preference android:title="Spoof test client" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
|
<Preference android:title="Spoof test client" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user