fix(YouTube - Spoof streaming data): Videos end 1 second early on iOS client

This commit is contained in:
inotia00
2024-12-17 13:57:19 +09:00
parent bb1946d9db
commit e0b6d33df5
7 changed files with 160 additions and 9 deletions

View File

@ -34,6 +34,10 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
const val EXTENSION_CLASS_DESCRIPTOR =
"$SPOOF_PATH/SpoofStreamingDataPatch;"
// In YouTube 17.34.36, this class is obfuscated.
const val STREAMING_DATA_INTERFACE =
"Lcom/google/protos/youtube/api/innertube/StreamingDataOuterClass${'$'}StreamingData;"
fun baseSpoofStreamingDataPatch(
block: BytecodePatchBuilder.() -> Unit = {},
executeBlock: BytecodePatchContext.() -> Unit = {},
@ -130,7 +134,8 @@ fun baseSpoofStreamingDataPatch(
if-eqz v2, :disabled
# Get streaming data.
invoke-static { v2 }, $EXTENSION_CLASS_DESCRIPTOR->getStreamingData(Ljava/lang/String;)Ljava/nio/ByteBuffer;
iget-object v6, p0, $setStreamingDataField
invoke-static { v2, v6 }, $EXTENSION_CLASS_DESCRIPTOR->getStreamingData(Ljava/lang/String;$STREAMING_DATA_INTERFACE)Ljava/nio/ByteBuffer;
move-result-object v3
if-eqz v3, :disabled
@ -154,6 +159,39 @@ fun baseSpoofStreamingDataPatch(
}
}
videoStreamingDataConstructorFingerprint.methodOrThrow(videoStreamingDataToStringFingerprint).apply {
val formatStreamModelInitIndex = indexOfFormatStreamModelInitInstruction(this)
val getVideoIdIndex = indexOfFirstInstructionReversedOrThrow(formatStreamModelInitIndex) {
val reference = getReference<FieldReference>()
opcode == Opcode.IGET_OBJECT &&
reference?.type == "Ljava/lang/String;" &&
reference.definingClass == definingClass
}
val getVideoIdReference = getInstruction<ReferenceInstruction>(getVideoIdIndex).reference
val insertIndex = indexOfFirstInstructionReversedOrThrow(getVideoIdIndex) {
opcode == Opcode.IGET_OBJECT &&
getReference<FieldReference>()?.definingClass == STREAMING_DATA_INTERFACE
}
val (freeRegister, streamingDataRegister) = with(getInstruction<TwoRegisterInstruction>(insertIndex)) {
Pair(registerA, registerB)
}
val definingClassRegister = getInstruction<TwoRegisterInstruction>(getVideoIdIndex).registerB
val insertReference = getInstruction<ReferenceInstruction>(insertIndex).reference
replaceInstruction(
insertIndex,
"iget-object v$freeRegister, v$freeRegister, $insertReference"
)
addInstructions(
insertIndex, """
iget-object v$freeRegister, v$definingClassRegister, $getVideoIdReference
invoke-static { v$freeRegister, v$streamingDataRegister }, $EXTENSION_CLASS_DESCRIPTOR->getOriginalStreamingData(Ljava/lang/String;$STREAMING_DATA_INTERFACE)$STREAMING_DATA_INTERFACE
move-result-object v$freeRegister
"""
)
}
// endregion
// region Remove /videoplayback request body to fix playback.

View File

@ -103,6 +103,34 @@ internal val protobufClassParseByteBufferFingerprint = legacyFingerprint(
customFingerprint = { method, _ -> method.name == "parseFrom" },
)
internal val videoStreamingDataConstructorFingerprint = legacyFingerprint(
name = "videoStreamingDataConstructorFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
returnType = "V",
customFingerprint = { method, _ ->
indexOfFormatStreamModelInitInstruction(method) >= 0
},
)
internal fun indexOfFormatStreamModelInitInstruction(method: Method) =
method.indexOfFirstInstruction {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_DIRECT &&
reference?.name == "<init>" &&
reference.parameterTypes.size > 1
}
internal val videoStreamingDataToStringFingerprint = legacyFingerprint(
name = "videoStreamingDataToStringFingerprint",
returnType = "Ljava/lang/String;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
strings = listOf("VideoStreamingData(itags="),
customFingerprint = { method, _ ->
method.name == "toString"
},
)
internal const val HLS_CURRENT_TIME_FEATURE_FLAG = 45355374L
internal val hlsCurrentTimeFingerprint = legacyFingerprint(