diff --git a/.releaserc b/.releaserc index e59b1143e..3ed71897a 100644 --- a/.releaserc +++ b/.releaserc @@ -39,7 +39,7 @@ [ "@saithodev/semantic-release-backmerge", { - backmergeBranches: [{"from": "dev", "to": "main"}], + backmergeBranches: [{"from": "main", "to": "dev"}], clearWorkspace: true } ] diff --git a/CHANGELOG.md b/CHANGELOG.md index c2062470c..d91dab423 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +# [2.164.0-dev.3](https://github.com/revanced/revanced-patches/compare/v2.164.0-dev.2...v2.164.0-dev.3) (2023-02-24) + + +### Features + +* **youtube/return-youtube-dislike:** support for shorts ([#1596](https://github.com/revanced/revanced-patches/issues/1596)) ([967c1cb](https://github.com/revanced/revanced-patches/commit/967c1cbd4b340a382a355f13d236d2881bafddbf)) + +# [2.164.0-dev.2](https://github.com/revanced/revanced-patches/compare/v2.164.0-dev.1...v2.164.0-dev.2) (2023-02-23) + + +### Features + +* **youtube/general-ads:** hide quick actions in fullscreen ([fff9670](https://github.com/revanced/revanced-patches/commit/fff9670a81108b8343d0b7913953fc6c2bb4a6f0)) +* **youtube/general-ads:** hide related videos in quick action ([d23c31a](https://github.com/revanced/revanced-patches/commit/d23c31a9ec39189e08474044ac5ca06d974add76)) + # [2.164.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.163.0...v2.164.0-dev.1) (2023-02-22) diff --git a/gradle.properties b/gradle.properties index 92dc70c37..e544a2043 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ kotlin.code.style = official -version = 2.164.0-dev.1 +version = 2.164.0-dev.3 diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralAdsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralAdsResourcePatch.kt index 3cb5ef79b..3c0bd695c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralAdsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralAdsResourcePatch.kt @@ -199,6 +199,27 @@ class GeneralAdsResourcePatch : ResourcePatch { StringResource("revanced_hide_channel_bar_summary_on", "Channel bar is hidden"), StringResource("revanced_hide_channel_bar_summary_off", "Channel bar is shown") ), + SwitchPreference( + "revanced_hide_quick_actions", + StringResource("revanced_hide_quick_actions_title", "Hide quick actions in fullscreen"), + false, + StringResource("revanced_hide_quick_actions_summary_on", "Quick actions are hidden"), + StringResource("revanced_hide_quick_actions_summary_off", "Quick actions are shown") + ), + SwitchPreference( + "revanced_hide_related_videos", + StringResource("revanced_hide_related_videos_title", "Hide related videos in quick actions"), + false, + StringResource("revanced_hide_related_videos_summary_on", "Related videos are hidden"), + StringResource("revanced_hide_related_videos_summary_off", "Related videos are shown") + ), + SwitchPreference( + "revanced_hide_channel_bar", + StringResource("revanced_hide_channel_bar_title", "Hide channel bar"), + false, + StringResource("revanced_hide_channel_bar_summary_on", "Channel bar is hidden"), + StringResource("revanced_hide_channel_bar_summary_off", "Channel bar is shown") + ), ) PreferenceScreen.ADS.addPreferences( diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextComponentParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextComponentParentFingerprint.kt new file mode 100644 index 000000000..7179eb3ac --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextComponentParentFingerprint.kt @@ -0,0 +1,25 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object ShortsTextComponentParentFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PROTECTED or AccessFlags.FINAL, + parameters = listOf("L", "L"), + opcodes = listOf( + Opcode.IF_EQZ, + Opcode.CONST_4, + Opcode.IF_EQ, + Opcode.CONST_4, + Opcode.IF_EQ, + Opcode.RETURN_VOID, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.IGET_BOOLEAN, + Opcode.IF_EQZ, + Opcode.INVOKE_STATIC + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt index 65d627465..6a63c83d0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt @@ -5,8 +5,10 @@ import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.data.toMethodWalker import app.revanced.patcher.extensions.MethodFingerprintExtensions.name import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.patch.BytecodePatch @@ -15,12 +17,15 @@ import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.* import app.revanced.patches.youtube.layout.returnyoutubedislike.resource.patch.ReturnYouTubeDislikeResourcePatch import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch +import org.jf.dexlib2.builder.instruction.BuilderInstruction35c +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction @Patch @DependsOn( @@ -38,55 +43,103 @@ import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch class ReturnYouTubeDislikePatch : BytecodePatch( listOf( TextComponentSpecParentFingerprint, + ShortsTextComponentParentFingerprint, LikeFingerprint, DislikeFingerprint, RemoveLikeFingerprint, ) ) { override fun execute(context: BytecodeContext): PatchResult { + // region Inject newVideoLoaded event handler + + VideoIdPatch.injectCall("$INTEGRATIONS_PATCH_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V") + + // endregion + + // region Hook interaction + listOf( LikeFingerprint.toPatch(Vote.LIKE), DislikeFingerprint.toPatch(Vote.DISLIKE), RemoveLikeFingerprint.toPatch(Vote.REMOVE_LIKE) ).forEach { (fingerprint, vote) -> - with(fingerprint.result ?: return PatchResultError("Failed to find ${fingerprint.name} method.")) { - mutableMethod.addInstructions( + fingerprint.result?.mutableMethod?.apply { + addInstructions( 0, """ const/4 v0, ${vote.value} - invoke-static {v0}, Lapp/revanced/integrations/patches/ReturnYouTubeDislikePatch;->sendVote(I)V + invoke-static {v0}, $INTEGRATIONS_PATCH_CLASS_DESCRIPTOR->sendVote(I)V """ ) - } + } ?: return PatchResultError("Failed to find ${fingerprint.name} method.") } - VideoIdPatch.injectCall("Lapp/revanced/integrations/patches/ReturnYouTubeDislikePatch;->newVideoLoaded(Ljava/lang/String;)V") + // endregion - with(TextComponentFingerprint - .apply { resolve(context, TextComponentSpecParentFingerprint.result!!.classDef) } - .result ?: return TextComponentFingerprint.toErrorResult() - ) { - val createComponentMethod = mutableMethod + // region Hook components - val conversionContextParam = 5 - val textRefParam = createComponentMethod.parameters.size - 2 - // insert index must be 0, otherwise UI does not updated correctly in some situations - // such as switching from full screen or when using previous/next overlay buttons. - val insertIndex = 0 + TextComponentFingerprint.also { it.resolve(context, TextComponentSpecParentFingerprint.result!!.classDef) } + .result?.let { + with(it.mutableMethod) { + val createComponentMethod = this + + val conversionContextParam = 5 + val textRefParam = createComponentMethod.parameters.size - 2 + // Insert index must be 0, otherwise UI does not updated correctly in some situations + // such as switching from full screen or when using previous/next overlay buttons. + val insertIndex = 0 + + createComponentMethod.addInstructions( + insertIndex, + """ + move-object/from16 v7, p$conversionContextParam + move-object/from16 v8, p$textRefParam + invoke-static {v7, v8}, $INTEGRATIONS_PATCH_CLASS_DESCRIPTOR->onComponentCreated(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;)V + """ + ) + } + } ?: return TextComponentFingerprint.toErrorResult() + + ShortsTextComponentParentFingerprint.result?.let { + context + .toMethodWalker(it.method) + .nextMethod(it.scanResult.patternScanResult!!.endIndex, true) + .getMethod().let { method -> + with(method as MutableMethod) { + // After walking, verify the found method is what's expected. + if (returnType != ("Ljava/lang/CharSequence;") || parameterTypes.size != 1) + return PatchResultError("Method signature did not match: $this $parameterTypes") + + val insertIndex = implementation!!.instructions.size - 1 + + val spannedParameterRegister = (instruction(insertIndex) as OneRegisterInstruction).registerA + val parameter = (instruction(insertIndex - 2) as BuilderInstruction35c).reference + + if (!parameter.toString().endsWith("Landroid/text/Spanned;")) + return PatchResultError("Method signature parameter did not match: $parameter") + + addInstructions( + insertIndex, + """ + invoke-static {v$spannedParameterRegister}, $INTEGRATIONS_PATCH_CLASS_DESCRIPTOR->onShortsComponentCreated(Landroid/text/Spanned;)Landroid/text/Spanned; + move-result-object v$spannedParameterRegister + """ + ) + } + } + } ?: return ShortsTextComponentParentFingerprint.toErrorResult() + + // endregion - createComponentMethod.addInstructions( - insertIndex, - """ - move-object/from16 v7, p$conversionContextParam - move-object/from16 v8, p$textRefParam - invoke-static {v7, v8}, Lapp/revanced/integrations/patches/ReturnYouTubeDislikePatch;->onComponentCreated(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;)V - """ - ) - } return PatchResultSuccess() } - private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind) + private companion object { + const val INTEGRATIONS_PATCH_CLASS_DESCRIPTOR = + "Lapp/revanced/integrations/patches/ReturnYouTubeDislikePatch;" + + private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind) + } private data class VotePatch(val fingerprint: MethodFingerprint, val voteKind: Vote) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprint.kt index b688fb7a0..bed9e90d3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprint.kt @@ -1,16 +1,31 @@ package app.revanced.patches.youtube.misc.video.videoid.fingerprint import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode +@FuzzyPatternScanMethod(2) object VideoIdFingerprint : MethodFingerprint( - "V", - AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC, - listOf("L"), - listOf(Opcode.INVOKE_INTERFACE), - customFingerprint = { - it.definingClass.endsWith("PlaybackLifecycleMonitor;") - } + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L"), + opcodes = listOf( + Opcode.IF_EQZ, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT + ), + null, + { it.definingClass.endsWith("SubtitlesOverlayPresenter;") } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt index da21078f2..9e6d1ed9d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.misc.video.videoid.patch +import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version @@ -22,17 +23,18 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction @Version("0.0.1") @DependsOn([IntegrationsPatch::class]) class VideoIdPatch : BytecodePatch( - listOf( - VideoIdFingerprint - ) + listOf(VideoIdFingerprint) ) { override fun execute(context: BytecodeContext): PatchResult { - with(VideoIdFingerprint.result!!) { - insertMethod = mutableMethod - insertIndex = scanResult.patternScanResult!!.endIndex + 2 + VideoIdFingerprint.result?.let { + val videoIdRegisterInstructionIndex = it.scanResult.patternScanResult!!.endIndex - videoIdRegister = (insertMethod.instruction(insertIndex - 1) as OneRegisterInstruction).registerA - } + with(it.mutableMethod) { + insertMethod = this + videoIdRegister = (instruction(videoIdRegisterInstructionIndex) as OneRegisterInstruction).registerA + insertIndex = videoIdRegisterInstructionIndex + 1 + } + } ?: return VideoIdFingerprint.toErrorResult() return PatchResultSuccess() } @@ -49,10 +51,15 @@ class VideoIdPatch : BytecodePatch( */ fun injectCall( methodDescriptor: String - ) = insertMethod.addInstructions( - insertIndex, // move-result-object offset - "invoke-static {v$videoIdRegister}, $methodDescriptor" - ) + ) { + insertMethod.addInstructions( + // TODO: The order has been proven to not be required, so remove the logic for keeping order. + // Keep injection calls in the order they're added: + // Increment index. So if additional injection calls are added, those calls run after this injection call. + insertIndex++, + "invoke-static {v$videoIdRegister}, $methodDescriptor" + ) + } } }