feat: downloads patch (#215)
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.annotation
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.27.39", "17.32.35")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class PlayerControlsCompatibility
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.impl.BytecodeData
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
|
||||
import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
||||
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
|
||||
import app.revanced.patches.youtube.misc.playercontrols.annotation.PlayerControlsCompatibility
|
||||
import app.revanced.patches.youtube.misc.playercontrols.fingerprints.BottomControlsInflateFingerprint
|
||||
import app.revanced.patches.youtube.misc.playercontrols.fingerprints.PlayerControlsVisibilityFingerprint
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Name("player-controls-bytecode-patch")
|
||||
@DependsOn([ResourceIdMappingProviderResourcePatch::class])
|
||||
@Description("Manages the code for the player controls of the YouTube player.")
|
||||
@PlayerControlsCompatibility
|
||||
@Version("0.0.1")
|
||||
class PlayerControlsBytecodePatch : BytecodePatch(
|
||||
listOf(PlayerControlsVisibilityFingerprint)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
showPlayerControlsFingerprintResult = PlayerControlsVisibilityFingerprint.result!!
|
||||
|
||||
bottomUiContainerResourceId = ResourceIdMappingProviderResourcePatch
|
||||
.resourceMappings
|
||||
.single { it.type == "id" && it.name == "bottom_ui_container_stub" }.id
|
||||
|
||||
// TODO: another solution is required, this is hacky
|
||||
listOf(BottomControlsInflateFingerprint).resolve(data, data.classes)
|
||||
inflateFingerprintResult = BottomControlsInflateFingerprint.result!!
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
var bottomUiContainerResourceId: Long = 0
|
||||
|
||||
lateinit var showPlayerControlsFingerprintResult: MethodFingerprintResult
|
||||
|
||||
private var inflateFingerprintResult: MethodFingerprintResult? = null
|
||||
set(fingerprint) {
|
||||
field = fingerprint!!.also {
|
||||
moveToRegisterInstructionIndex = it.patternScanResult!!.endIndex
|
||||
viewRegister =
|
||||
(it.mutableMethod.implementation!!.instructions[moveToRegisterInstructionIndex] as OneRegisterInstruction).registerA
|
||||
}
|
||||
}
|
||||
|
||||
private var moveToRegisterInstructionIndex: Int = 0
|
||||
private var viewRegister: Int = 0
|
||||
|
||||
/**
|
||||
* Injects the code to change the visibility of controls.
|
||||
* @param descriptor The descriptor of the method which should be called.
|
||||
*/
|
||||
fun injectVisibilityCheckCall(descriptor: String) {
|
||||
showPlayerControlsFingerprintResult.mutableMethod.addInstruction(
|
||||
0,
|
||||
"""
|
||||
invoke-static {p1}, $descriptor
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the code to initialize the controls.
|
||||
* @param descriptor The descriptor of the method which should be calleed.
|
||||
*/
|
||||
fun initializeControl(descriptor: String) {
|
||||
inflateFingerprintResult!!.mutableMethod.addInstruction(
|
||||
moveToRegisterInstructionIndex + 1,
|
||||
"invoke-static {v$viewRegister}, $descriptor"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.fingerprints
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.playercontrols.annotation.PlayerControlsCompatibility
|
||||
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||
|
||||
@Name("bottom-controls-inflate-fingerprint")
|
||||
@MatchingMethod(
|
||||
"Lknf;", "a"
|
||||
)
|
||||
@DirectPatternScanMethod
|
||||
@PlayerControlsCompatibility
|
||||
@Version("0.0.1")
|
||||
object BottomControlsInflateFingerprint : MethodFingerprint(
|
||||
null, null, null, listOf(
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
), null,
|
||||
{ methodDef ->
|
||||
methodDef.implementation?.instructions?.any { instruction ->
|
||||
(instruction as? WideLiteralInstruction)?.wideLiteral == PlayerControlsBytecodePatch.bottomUiContainerResourceId
|
||||
} == true
|
||||
}
|
||||
)
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.fingerprints
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.playercontrols.annotation.PlayerControlsCompatibility
|
||||
|
||||
@Name("player-controls-visibility-fingerprint")
|
||||
@MatchingMethod(
|
||||
"LYouTubeControlsOverlay;", "ag"
|
||||
)
|
||||
@DirectPatternScanMethod
|
||||
@PlayerControlsCompatibility
|
||||
@Version("0.0.1")
|
||||
object PlayerControlsVisibilityFingerprint : MethodFingerprint(
|
||||
"V", null, listOf("Z", "Z"), null, null, { methodDef ->
|
||||
methodDef.definingClass.endsWith("YouTubeControlsOverlay;")
|
||||
}
|
||||
)
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.resource.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.impl.DomFileEditor
|
||||
import app.revanced.patcher.data.impl.ResourceData
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.impl.ResourcePatch
|
||||
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
|
||||
import app.revanced.patches.youtube.misc.playercontrols.annotation.PlayerControlsCompatibility
|
||||
import java.io.Closeable
|
||||
|
||||
@Name("bottom-controls-resource-patch")
|
||||
@DependsOn([FixLocaleConfigErrorPatch::class])
|
||||
@Description("Manages the resources for the bottom controls of the YouTube player.")
|
||||
@PlayerControlsCompatibility
|
||||
@Version("0.0.1")
|
||||
class BottomControlsResourcePatch : ResourcePatch(), Closeable {
|
||||
override fun execute(data: ResourceData): PatchResult {
|
||||
resourceData = data
|
||||
targetXmlEditor = data.xmlEditor[TARGET_RESOURCE]
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal const val TARGET_RESOURCE_NAME = "youtube_controls_bottom_ui_container.xml"
|
||||
private const val TARGET_RESOURCE = "res/layout/$TARGET_RESOURCE_NAME"
|
||||
|
||||
private lateinit var resourceData: ResourceData
|
||||
private lateinit var targetXmlEditor: DomFileEditor
|
||||
|
||||
// The element to which to add the new elements to
|
||||
private var lastLeftOf = "fullscreen_button"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add new controls to the bottom of the YouTube player.
|
||||
* @param hostYouTubeControlsBottomUiResourceName The hosting resource name containing the elements.
|
||||
*/
|
||||
internal fun addControls(hostYouTubeControlsBottomUiResourceName: String) {
|
||||
val sourceXmlEditor =
|
||||
resourceData.xmlEditor[this::class.java.classLoader.getResourceAsStream(
|
||||
hostYouTubeControlsBottomUiResourceName
|
||||
)!!]
|
||||
|
||||
val targetElement =
|
||||
"android.support.constraint.ConstraintLayout"
|
||||
|
||||
val hostElements = sourceXmlEditor.file.getElementsByTagName(targetElement).item(0).childNodes
|
||||
|
||||
val destinationResourceFile = this.targetXmlEditor.file
|
||||
val destinationElement =
|
||||
destinationResourceFile.getElementsByTagName(targetElement).item(0)
|
||||
|
||||
for (index in 1 until hostElements.length) {
|
||||
val element = hostElements.item(index).cloneNode(true)
|
||||
|
||||
// if the element has no attributes theres no point to adding it to the destination
|
||||
if (!element.hasAttributes()) continue
|
||||
|
||||
// set the elements lastLeftOf attribute to the lastLeftOf value
|
||||
val namespace = "@+id"
|
||||
element.attributes.getNamedItem("yt:layout_constraintRight_toLeftOf").nodeValue =
|
||||
"$namespace/$lastLeftOf"
|
||||
|
||||
// set lastLeftOf attribute to the the current element
|
||||
val nameSpaceLength = 4
|
||||
lastLeftOf = element.attributes.getNamedItem("android:id").nodeValue.substring(nameSpaceLength)
|
||||
|
||||
// copy the element
|
||||
destinationResourceFile.adoptNode(element)
|
||||
destinationElement.appendChild(element)
|
||||
}
|
||||
sourceXmlEditor.close()
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
targetXmlEditor.close()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user