Skip to content

Commit 5b1e07d

Browse files
zainarbaniLisoUseInAIKyriosoSumAtrIX
authored
fix(YouTube): Fix issues related to playback by replace streaming data (#3582)
Co-authored-by: LisoUseInAIKyrios <[email protected]> Co-authored-by: oSumAtrIX <[email protected]>
1 parent e3220cc commit 5b1e07d

30 files changed

+427
-1126
lines changed

api/revanced-patches.api

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,6 +1916,12 @@ public final class app/revanced/patches/youtube/misc/fix/playback/SpoofSignature
19161916
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
19171917
}
19181918

1919+
public final class app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch : app/revanced/patcher/patch/BytecodePatch {
1920+
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch;
1921+
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
1922+
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
1923+
}
1924+
19191925
public final class app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch {
19201926
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch;
19211927
public synthetic fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Ljava/lang/Object;

src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt

Lines changed: 4 additions & 392 deletions
Large diffs are not rendered by default.
Lines changed: 4 additions & 231 deletions
Original file line numberDiff line numberDiff line change
@@ -1,239 +1,12 @@
11
package app.revanced.patches.youtube.misc.fix.playback
22

33
import app.revanced.patcher.data.BytecodeContext
4-
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
5-
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
6-
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
7-
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
84
import app.revanced.patcher.patch.BytecodePatch
9-
import app.revanced.patcher.patch.annotation.Patch
10-
import app.revanced.patcher.util.smali.ExternalLabel
11-
import app.revanced.patches.all.misc.resources.AddResourcesPatch
12-
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
13-
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
14-
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
15-
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.*
16-
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
17-
import app.revanced.patches.youtube.misc.settings.SettingsPatch
18-
import app.revanced.patches.youtube.video.information.VideoInformationPatch
19-
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
20-
import app.revanced.util.exception
21-
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
22-
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
23-
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
245

25-
@Patch(
26-
description = "Spoofs the signature to prevent playback issues.",
27-
dependencies = [
28-
SettingsPatch::class,
29-
PlayerTypeHookPatch::class,
30-
PlayerResponseMethodHookPatch::class,
31-
VideoInformationPatch::class,
32-
SpoofSignatureResourcePatch::class,
33-
AddResourcesPatch::class,
34-
],
35-
)
36-
@Deprecated("This patch will be removed in the future.")
6+
@Deprecated("This patch is obsolete.", replaceWith = ReplaceWith("SpoofVideoStreamsPatch"))
377
object SpoofSignaturePatch : BytecodePatch(
38-
setOf(
39-
PlayerResponseModelImplGeneralFingerprint,
40-
PlayerResponseModelImplLiveStreamFingerprint,
41-
PlayerResponseModelImplRecommendedLevelFingerprint,
42-
StoryboardRendererSpecFingerprint,
43-
StoryboardRendererDecoderSpecFingerprint,
44-
StoryboardRendererDecoderRecommendedLevelFingerprint,
45-
StoryboardThumbnailParentFingerprint,
46-
SpoofSignaturePatchScrubbedPreviewLayoutFingerprint,
47-
StatsQueryParameterFingerprint,
48-
ParamsMapPutFingerprint,
49-
),
8+
dependencies = setOf(SpoofVideoStreamsPatch::class),
509
) {
51-
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
52-
"Lapp/revanced/integrations/youtube/patches/spoof/SpoofSignaturePatch;"
53-
54-
override fun execute(context: BytecodeContext) {
55-
AddResourcesPatch(this::class)
56-
57-
SettingsPatch.PreferenceScreen.MISC.addPreferences(
58-
PreferenceScreen(
59-
key = "revanced_spoof_signature_verification_screen",
60-
sorting = Sorting.UNSORTED,
61-
preferences = setOf(
62-
SwitchPreference("revanced_spoof_signature_verification_enabled"),
63-
SwitchPreference("revanced_spoof_signature_in_feed_enabled"),
64-
SwitchPreference("revanced_spoof_storyboard"),
65-
),
66-
),
67-
)
68-
69-
// Hook the player parameters.
70-
PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.ProtoBufferParameter(
71-
"$INTEGRATIONS_CLASS_DESCRIPTOR->spoofParameter(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;",
72-
)
73-
74-
// Force the seekbar time and chapters to always show up.
75-
// This is used if the storyboard spec fetch fails, for viewing paid videos,
76-
// or if storyboard spoofing is turned off.
77-
StoryboardThumbnailParentFingerprint.result?.classDef?.let { classDef ->
78-
StoryboardThumbnailFingerprint.also {
79-
it.resolve(
80-
context,
81-
classDef,
82-
)
83-
}.result?.let {
84-
val endIndex = it.scanResult.patternScanResult!!.endIndex
85-
// Replace existing instruction to preserve control flow label.
86-
// The replaced return instruction always returns false
87-
// (it is the 'no thumbnails found' control path),
88-
// so there is no need to pass the existing return value to integrations.
89-
it.mutableMethod.replaceInstruction(
90-
endIndex,
91-
"""
92-
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarThumbnailOverrideValue()Z
93-
""",
94-
)
95-
// Since this is end of the method must replace one line then add the rest.
96-
it.mutableMethod.addInstructions(
97-
endIndex + 1,
98-
"""
99-
move-result v0
100-
return v0
101-
""",
102-
)
103-
} ?: throw StoryboardThumbnailFingerprint.exception
104-
}
105-
106-
// If storyboard spoofing is turned off, then hide the empty seekbar thumbnail view.
107-
SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.result?.apply {
108-
val endIndex = scanResult.patternScanResult!!.endIndex
109-
mutableMethod.apply {
110-
val imageViewFieldName = getInstruction<ReferenceInstruction>(endIndex).reference
111-
addInstructions(
112-
implementation!!.instructions.lastIndex,
113-
"""
114-
iget-object v0, p0, $imageViewFieldName # copy imageview field to a register
115-
invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->seekbarImageViewCreated(Landroid/widget/ImageView;)V
116-
""",
117-
)
118-
}
119-
} ?: throw SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.exception
120-
121-
/**
122-
* Hook StoryBoard renderer url
123-
*/
124-
arrayOf(
125-
PlayerResponseModelImplGeneralFingerprint,
126-
PlayerResponseModelImplLiveStreamFingerprint,
127-
).forEach { fingerprint ->
128-
fingerprint.result?.let {
129-
it.mutableMethod.apply {
130-
val getStoryBoardIndex = it.scanResult.patternScanResult!!.endIndex
131-
val getStoryBoardRegister =
132-
getInstruction<OneRegisterInstruction>(getStoryBoardIndex).registerA
133-
134-
addInstructions(
135-
getStoryBoardIndex,
136-
"""
137-
invoke-static { v$getStoryBoardRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String;
138-
move-result-object v$getStoryBoardRegister
139-
""",
140-
)
141-
}
142-
} ?: throw fingerprint.exception
143-
}
144-
145-
// Hook recommended seekbar thumbnails quality level.
146-
StoryboardRendererDecoderRecommendedLevelFingerprint.result?.let {
147-
val moveOriginalRecommendedValueIndex = it.scanResult.patternScanResult!!.endIndex
148-
val originalValueRegister = it.mutableMethod
149-
.getInstruction<OneRegisterInstruction>(moveOriginalRecommendedValueIndex).registerA
150-
151-
it.mutableMethod.addInstructions(
152-
moveOriginalRecommendedValueIndex + 1,
153-
"""
154-
invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I
155-
move-result v$originalValueRegister
156-
""",
157-
)
158-
} ?: throw StoryboardRendererDecoderRecommendedLevelFingerprint.exception
159-
160-
// Hook the recommended precise seeking thumbnails quality level.
161-
PlayerResponseModelImplRecommendedLevelFingerprint.result?.let {
162-
it.mutableMethod.apply {
163-
val moveOriginalRecommendedValueIndex = it.scanResult.patternScanResult!!.endIndex
164-
val originalValueRegister =
165-
getInstruction<OneRegisterInstruction>(moveOriginalRecommendedValueIndex).registerA
166-
167-
addInstructions(
168-
moveOriginalRecommendedValueIndex,
169-
"""
170-
invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I
171-
move-result v$originalValueRegister
172-
""",
173-
)
174-
}
175-
} ?: throw PlayerResponseModelImplRecommendedLevelFingerprint.exception
176-
177-
StoryboardRendererSpecFingerprint.result?.let {
178-
it.mutableMethod.apply {
179-
val storyBoardUrlParams = 0
180-
181-
addInstructionsWithLabels(
182-
0,
183-
"""
184-
if-nez p$storyBoardUrlParams, :ignore
185-
invoke-static { p$storyBoardUrlParams }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String;
186-
move-result-object p$storyBoardUrlParams
187-
""",
188-
ExternalLabel("ignore", getInstruction(0)),
189-
)
190-
}
191-
} ?: throw StoryboardRendererSpecFingerprint.exception
192-
193-
// Hook the seekbar thumbnail decoder and use a NULL spec for live streams.
194-
StoryboardRendererDecoderSpecFingerprint.result?.let {
195-
val storyBoardUrlIndex = it.scanResult.patternScanResult!!.startIndex + 1
196-
val storyboardUrlRegister =
197-
it.mutableMethod.getInstruction<OneRegisterInstruction>(storyBoardUrlIndex).registerA
198-
199-
it.mutableMethod.addInstructions(
200-
storyBoardUrlIndex + 1,
201-
"""
202-
invoke-static { v$storyboardUrlRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardDecoderRendererSpec(Ljava/lang/String;)Ljava/lang/String;
203-
move-result-object v$storyboardUrlRegister
204-
""",
205-
)
206-
} ?: throw StoryboardRendererDecoderSpecFingerprint.exception
207-
208-
// Fix stats not being tracked.
209-
// Due to signature spoofing "adformat" is present in query parameters made for /stats requests,
210-
// even though, for regular videos, it should not be.
211-
// This breaks stats tracking.
212-
// Replace the ad parameter with the video parameter in the query parameters.
213-
StatsQueryParameterFingerprint.result?.let {
214-
val putMethod = ParamsMapPutFingerprint.result?.method?.toString()
215-
?: throw ParamsMapPutFingerprint.exception
216-
217-
it.mutableMethod.apply {
218-
val adParamIndex = it.scanResult.stringsScanResult!!.matches.first().index
219-
val videoParamIndex = adParamIndex + 3
220-
221-
// Replace the ad parameter with the video parameter.
222-
replaceInstruction(adParamIndex, getInstruction(videoParamIndex))
223-
224-
// Call paramsMap.put instead of paramsMap.putIfNotExist
225-
// because the key is already present in the map.
226-
val putAdParamIndex = adParamIndex + 1
227-
val putIfKeyNotExistsInstruction = getInstruction<FiveRegisterInstruction>(putAdParamIndex)
228-
replaceInstruction(
229-
putAdParamIndex,
230-
"invoke-virtual { " +
231-
"v${putIfKeyNotExistsInstruction.registerC}, " +
232-
"v${putIfKeyNotExistsInstruction.registerD}, " +
233-
"v${putIfKeyNotExistsInstruction.registerE} }, " +
234-
putMethod,
235-
)
236-
}
237-
} ?: throw StatsQueryParameterFingerprint.exception
238-
}
10+
override fun execute(context: BytecodeContext) {}
23911
}
12+

src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignatureResourcePatch.kt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,8 @@ package app.revanced.patches.youtube.misc.fix.playback
22

33
import app.revanced.patcher.data.ResourceContext
44
import app.revanced.patcher.patch.ResourcePatch
5-
import app.revanced.patcher.patch.annotation.Patch
6-
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
75

8-
@Patch(dependencies = [ResourceMappingPatch::class])
96
@Deprecated("This patch will be removed in the future.")
107
object SpoofSignatureResourcePatch : ResourcePatch() {
11-
internal var scrubbedPreviewThumbnailResourceId: Long = -1
12-
13-
override fun execute(context: ResourceContext) {
14-
scrubbedPreviewThumbnailResourceId = ResourceMappingPatch[
15-
"id",
16-
"thumbnail",
17-
]
18-
}
8+
override fun execute(context: ResourceContext) {}
199
}

0 commit comments

Comments
 (0)