From 36af4cc14ff8057c10b99019cb23acc6e5aec3f2 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 18 Jul 2022 01:17:03 +0200 Subject: [PATCH] feat: `sponsorblock` patch (#101) * chore(release): 2.5.1-dev.1 [skip ci] ## [2.5.1-dev.1](https://github.com/revanced/revanced-patches/compare/v2.5.0...v2.5.1-dev.1) (2022-06-30) ### Bug Fixes * freezing panels when watching video in fullscreen ([#89](https://github.com/revanced/revanced-patches/issues/89)) ([f5d4f6c](https://github.com/revanced/revanced-patches/commit/f5d4f6c3419916c6a9cf67babc6be8a64c854d3b)) * invalid version in compatibility annotation ([#90](https://github.com/revanced/revanced-patches/issues/90)) ([df43547](https://github.com/revanced/revanced-patches/commit/df435475cdd0494a1e4ea9e2980c2998c9bc7048)) * feat: migrate to breaking changes of patcher * chore(release): 2.6.0-dev.1 [skip ci] # [2.6.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.5.1-dev.1...v2.6.0-dev.1) (2022-07-02) ### Features * migrate to breaking changes of patcher ([a116852](https://github.com/revanced/revanced-patches/commit/a11685263fb2274c67684258e73c5247502cb010)) * refactor: add package for fingerprints * feat: partial `sponsorblock` patch * feat: add `Name` annotation to `sponsorblock-resource-patch` * fix: `sponsorblock-resource-patch` * refactor: remove unused resources * refactor: remove `locale-config-fix` dependency * fix: broken fingerprints * feat: general fixes on `sponsorblock` patch * feat: more fixes on `sponsorblock` patch * feat: update `sponsorblock` patch to 17.26.35 * style: use better wording and fix spelling mistakes * fix: finish `sponsorblock` patch Co-authored-by: semantic-release-bot --- .../resource/patch/GeneralResourceAdsPatch.kt | 0 .../annotations/SponsorBlockCompatibility.kt | 13 + .../fingerprints/AppendTimeFingerprint.kt | 41 +++ .../CreateVideoPlayerSeekbarFingerprint.kt | 21 ++ .../NextGenWatchLayoutFingerprint.kt | 24 ++ ...erControllerSetTimeReferenceFingerprint.kt | 22 ++ .../fingerprints/PlayerInitFingerprint.kt | 23 ++ .../PlayerOverlaysLayoutInitFingerprint.kt | 22 ++ .../RectangleFieldInvalidatorFingerprint.kt | 37 ++ .../bytecode/fingerprints/SeekFingerprint.kt | 23 ++ .../ShowPlayerControlsFingerprint.kt | 19 + .../fingerprints/VideoLengthFingerprint.kt | 34 ++ .../fingerprints/VideoTimeFingerprint.kt | 20 ++ .../patch/SponsorBlockBytecodePatch.kt | 335 ++++++++++++++++++ .../patch/SponsorBlockResourcePatch.kt | 128 +++++++ .../misc/videoid/patch/VideoIdPatch.kt | 20 +- .../sponsorblock/drawable/ic_sb_adjust.xml | 10 + .../sponsorblock/drawable/ic_sb_compare.xml | 10 + .../sponsorblock/drawable/ic_sb_edit.xml | 10 + .../sponsorblock/drawable/ic_sb_logo.xml | 19 + .../sponsorblock/drawable/ic_sb_publish.xml | 10 + .../sponsorblock/drawable/ic_sb_voting.xml | 10 + .../host/layout/youtube_controls_layout.xml | 4 + .../layout/inline_sponsor_overlay.xml | 5 + .../sponsorblock/layout/new_segment.xml | 107 ++++++ .../layout/skip_sponsor_button.xml | 7 + .../resources/sponsorblock/values/strings.xml | 182 ++++++++++ 27 files changed, 1149 insertions(+), 7 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralResourceAdsPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/AppendTimeFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerInitFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/SeekFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/ShowPlayerControlsFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/VideoLengthFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/VideoTimeFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt create mode 100644 src/main/resources/sponsorblock/drawable/ic_sb_adjust.xml create mode 100644 src/main/resources/sponsorblock/drawable/ic_sb_compare.xml create mode 100644 src/main/resources/sponsorblock/drawable/ic_sb_edit.xml create mode 100644 src/main/resources/sponsorblock/drawable/ic_sb_logo.xml create mode 100644 src/main/resources/sponsorblock/drawable/ic_sb_publish.xml create mode 100644 src/main/resources/sponsorblock/drawable/ic_sb_voting.xml create mode 100644 src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml create mode 100644 src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml create mode 100644 src/main/resources/sponsorblock/layout/new_segment.xml create mode 100644 src/main/resources/sponsorblock/layout/skip_sponsor_button.xml create mode 100644 src/main/resources/sponsorblock/values/strings.xml diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralResourceAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralResourceAdsPatch.kt new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt new file mode 100644 index 000000000..2662048d4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.layout.sponsorblock.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility( + [Package( + "com.google.android.youtube", arrayOf("17.22.36", "17.26.35", "17.27.39") + )] +) +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +internal annotation class SponsorBlockCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/AppendTimeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/AppendTimeFingerprint.kt new file mode 100644 index 000000000..5faa9c1b1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/AppendTimeFingerprint.kt @@ -0,0 +1,41 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.extensions.or +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.layout.sponsorblock.annotations.SponsorBlockCompatibility +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +@Name("append-time-fingerprint") +@MatchingMethod( + "Liet;", "e" +) +@DirectPatternScanMethod +@SponsorBlockCompatibility +@Version("0.0.1") +object AppendTimeFingerprint : MethodFingerprint( + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("L", "L", "L"), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.RETURN_VOID + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt new file mode 100644 index 000000000..eafd1e674 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt @@ -0,0 +1,21 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.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.layout.sponsorblock.annotations.SponsorBlockCompatibility + +@Name("create-video-player-seekbar-fingerprint") +@MatchingMethod( + "Lfcm;", "onDraw" +) +@DirectPatternScanMethod +@SponsorBlockCompatibility +@Version("0.0.1") +object CreateVideoPlayerSeekbarFingerprint : MethodFingerprint( + "V", null, null, + null, + listOf("timed_markers_width") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt new file mode 100644 index 000000000..013d21025 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt @@ -0,0 +1,24 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.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.layout.sponsorblock.annotations.SponsorBlockCompatibility +import org.jf.dexlib2.util.MethodUtil + +@Name("next-gen-watch-layout-fingerprint") +@MatchingMethod( + "LNextGenWatchLayout;", "" +) +@DirectPatternScanMethod +@SponsorBlockCompatibility +@Version("0.0.1") +object NextGenWatchLayoutFingerprint : MethodFingerprint( + "V", // constructors return void, in favour of speed of matching, this fingerprint has been added + null, + null, + null, + customFingerprint = { methodDef -> MethodUtil.isConstructor(methodDef) && methodDef.parameterTypes.size == 3 && methodDef.definingClass.endsWith("NextGenWatchLayout;") } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt new file mode 100644 index 000000000..9b4127782 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt @@ -0,0 +1,22 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.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.layout.sponsorblock.annotations.SponsorBlockCompatibility +import org.jf.dexlib2.Opcode + +@Name("player-controller-set-time-reference-fingerprint") +@MatchingMethod( + "Lxqm;", "" +) +@DirectPatternScanMethod +@SponsorBlockCompatibility +@Version("0.0.1") +object PlayerControllerSetTimeReferenceFingerprint : MethodFingerprint( + null, null, null, + listOf(Opcode.INVOKE_DIRECT_RANGE, Opcode.IGET_OBJECT), + listOf("Media progress reported outside media playback: ") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerInitFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerInitFingerprint.kt new file mode 100644 index 000000000..edd04188d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerInitFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.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.layout.sponsorblock.annotations.SponsorBlockCompatibility + +@Name("player-init-fingerprint") +@MatchingMethod( + "Laajv;", "aG" +) +@DirectPatternScanMethod +@SponsorBlockCompatibility +@Version("0.0.1") +object PlayerInitFingerprint : MethodFingerprint( + null, null, null, + null, + strings = listOf( + "playVideo called on player response with no videoStreamingData." + ), +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt new file mode 100644 index 000000000..375480287 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt @@ -0,0 +1,22 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.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.layout.sponsorblock.annotations.SponsorBlockCompatibility + +@Name("player-overlays-layout-init-fingerprint") +@MatchingMethod( + "Lihh;", "u" +) +@DirectPatternScanMethod +@SponsorBlockCompatibility +@Version("0.0.1") +object PlayerOverlaysLayoutInitFingerprint : MethodFingerprint( + null, null, null, + null, + null, + { methodDef -> methodDef.returnType.endsWith("YouTubePlayerOverlaysLayout;") } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt new file mode 100644 index 000000000..e7425a95d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt @@ -0,0 +1,37 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.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.layout.sponsorblock.annotations.SponsorBlockCompatibility +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.MethodReference + +@Name("rectangle-field-invalidator-fingerprint") +@MatchingMethod( + "Lfcm;", "kY" +) +@DirectPatternScanMethod +@SponsorBlockCompatibility +@Version("0.0.1") +object RectangleFieldInvalidatorFingerprint : MethodFingerprint( + "V", + null, + null, + null, + null, + custom@{ methodDef -> + val instructions = methodDef.implementation?.instructions!! + val instructionCount = instructions.count() + + // the method has definitely more than 5 instructions + if (instructionCount < 5) return@custom false + + val referenceInstruction = instructions.elementAt(instructionCount - 2) // the second to last instruction + val reference = ((referenceInstruction as? ReferenceInstruction)?.reference as? MethodReference) + + reference?.parameterTypes?.size == 1 && reference.name == "invalidate" // the reference is the invalidate(..) method + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/SeekFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/SeekFingerprint.kt new file mode 100644 index 000000000..855bbe042 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/SeekFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.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.layout.sponsorblock.annotations.SponsorBlockCompatibility + +@Name("seek-fingerprint") +@MatchingMethod( + "Laajv;", "af" +) +@DirectPatternScanMethod +@SponsorBlockCompatibility +@Version("0.0.1") +object SeekFingerprint : MethodFingerprint( + null, + null, + null, + null, + listOf("Attempting to seek during an ad") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/ShowPlayerControlsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/ShowPlayerControlsFingerprint.kt new file mode 100644 index 000000000..39c330aee --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/ShowPlayerControlsFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.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.layout.sponsorblock.annotations.SponsorBlockCompatibility + +@Name("show-player-controls-fingerprint") +@MatchingMethod( + "LYouTubeControlsOverlay;", "ac" +) +@DirectPatternScanMethod +@SponsorBlockCompatibility +@Version("0.0.1") +object ShowPlayerControlsFingerprint : MethodFingerprint( + "V", null, listOf("Z","Z"), null, null +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/VideoLengthFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/VideoLengthFingerprint.kt new file mode 100644 index 000000000..38085c210 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/VideoLengthFingerprint.kt @@ -0,0 +1,34 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.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.layout.sponsorblock.annotations.SponsorBlockCompatibility +import org.jf.dexlib2.Opcode + +@Name("video-length-fingerprint") +@MatchingMethod( + "Lyfh;", "z" +) +@DirectPatternScanMethod +@SponsorBlockCompatibility +@Version("0.0.1") +object VideoLengthFingerprint : MethodFingerprint( + null, null, null, + listOf( + Opcode.MOVE_RESULT_WIDE, + Opcode.CMP_LONG, + Opcode.IF_LEZ, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_WIDE, + Opcode.GOTO, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_WIDE, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/VideoTimeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/VideoTimeFingerprint.kt new file mode 100644 index 000000000..32f59cc03 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/VideoTimeFingerprint.kt @@ -0,0 +1,20 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.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.layout.sponsorblock.annotations.SponsorBlockCompatibility + +@Name("video-time-fingerprint") +@MatchingMethod( + "Lwyh;", "" +) +@DirectPatternScanMethod +@SponsorBlockCompatibility +@Version("0.0.1") +object VideoTimeFingerprint : MethodFingerprint( + null, null, null, null, + listOf("MedialibPlayerTimeInfo{currentPositionMillis=") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt new file mode 100644 index 000000000..718eb733d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt @@ -0,0 +1,335 @@ +package app.revanced.patches.youtube.layout.sponsorblock.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.data.impl.toMethodWalker +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.extensions.replaceInstruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +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.Dependencies +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.impl.BytecodePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility +import app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints.* +import app.revanced.patches.youtube.layout.sponsorblock.resource.patch.SponsorBlockResourcePatch +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch +import app.revanced.patches.youtube.misc.videoid.patch.VideoIdPatch +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.builder.MutableMethodImplementation +import org.jf.dexlib2.iface.instruction.* +import org.jf.dexlib2.iface.instruction.formats.Instruction35c +import org.jf.dexlib2.iface.reference.FieldReference +import org.jf.dexlib2.iface.reference.MethodReference +import org.jf.dexlib2.iface.reference.StringReference +import org.jf.dexlib2.immutable.ImmutableMethod +import org.jf.dexlib2.immutable.ImmutableMethodParameter +import org.jf.dexlib2.util.MethodUtil + +@Patch +@Dependencies( + dependencies = [IntegrationsPatch::class, ResourceIdMappingProviderResourcePatch::class, SponsorBlockResourcePatch::class, VideoIdPatch::class] +) +@Name("sponsorblock") +@Description("Integrate SponsorBlock.") +@SponsorBlockCompatibility +@Version("0.0.1") +class SponsorBlockBytecodePatch : BytecodePatch( + listOf( + PlayerControllerSetTimeReferenceFingerprint, + CreateVideoPlayerSeekbarFingerprint, + VideoTimeFingerprint, + NextGenWatchLayoutFingerprint, + AppendTimeFingerprint, + PlayerInitFingerprint, + PlayerOverlaysLayoutInitFingerprint + ) +) { + override fun execute(data: BytecodeData): PatchResult {/* + Set current video time + */ + val referenceResult = PlayerControllerSetTimeReferenceFingerprint.result!! + val playerControllerSetTimeMethod = + data.toMethodWalker(referenceResult.method).nextMethod(referenceResult.patternScanResult!!.startIndex, true) + .getMethod() as MutableMethod + playerControllerSetTimeMethod.addInstruction( + 2, + "invoke-static {p1, p2}, Lapp/revanced/integrations/sponsorblock/PlayerController;->setCurrentVideoTime(J)V" + ) + + /* + Set current video time high precision + */ + val constructorFingerprint = + object : MethodFingerprint("V", null, listOf("J", "J", "J", "J", "I", "L"), null) {} + constructorFingerprint.resolve(data, VideoTimeFingerprint.result!!.classDef) + + val constructor = constructorFingerprint.result!!.mutableMethod + constructor.addInstruction( + 0, + "invoke-static {p1, p2}, Lapp/revanced/integrations/sponsorblock/PlayerController;->setCurrentVideoTimeHighPrecision(J)V" + ) + + /* + Set current video id + */ + VideoIdPatch.injectCall("Lapp/revanced/integrations/sponsorblock/PlayerController;->setCurrentVideoId(Ljava/lang/String;)V") + + /* + Seekbar drawing + */ + val seekbarSignatureResult = CreateVideoPlayerSeekbarFingerprint.result!! + val seekbarMethod = seekbarSignatureResult.mutableMethod + val seekbarMethodInstructions = seekbarMethod.implementation!!.instructions + + /* + Get the instance of the seekbar rectangle + */ + seekbarMethod.addInstruction( + 1, + "invoke-static {v0}, Lapp/revanced/integrations/sponsorblock/PlayerController;->setSponsorBarRect(Ljava/lang/Object;)V" + ) + + for ((index, instruction) in seekbarMethodInstructions.withIndex()) { + if (instruction.opcode != Opcode.INVOKE_STATIC) continue + + val invokeInstruction = instruction as Instruction35c + if ((invokeInstruction.reference as MethodReference).name != "round") continue + + val insertIndex = index + 2 + + // set the thickness of the segment + seekbarMethod.addInstruction( + insertIndex, + "invoke-static {v${invokeInstruction.registerC}}, Lapp/revanced/integrations/sponsorblock/PlayerController;->setSponsorBarThickness(I)V" + ) + break + } + + /* + Set rectangle absolute left and right positions + */ + val drawRectangleInstructions = seekbarMethodInstructions.filter { + it is ReferenceInstruction && (it.reference as? MethodReference)?.name == "drawRect" && it is FiveRegisterInstruction + }.map { // TODO: improve code + seekbarMethodInstructions.indexOf(it) to (it as FiveRegisterInstruction).registerD + } + + val (indexRight, rectangleRightRegister) = drawRectangleInstructions[0] + val (indexLeft, rectangleLeftRegister) = drawRectangleInstructions[3] + + // order of operation is important here due to the code above which has to be improved + // the reason for that is that we get the index, add instructions and then the offset would be wrong + seekbarMethod.addInstruction( + indexLeft + 1, + "invoke-static {v$rectangleLeftRegister}, Lapp/revanced/integrations/sponsorblock/PlayerController;->setSponsorBarAbsoluteLeft(Landroid/graphics/Rect;)V" + ) + seekbarMethod.addInstruction( + indexRight + 1, + "invoke-static {v$rectangleRightRegister}, Lapp/revanced/integrations/sponsorblock/PlayerController;->setSponsorBarAbsoluteRight(Landroid/graphics/Rect;)V" + ) + + /* + Draw segment + */ + val drawSegmentInstructionInsertIndex = (seekbarMethodInstructions.size - 1 - 2) + val (canvasInstance, centerY) = (seekbarMethodInstructions[drawSegmentInstructionInsertIndex] as FiveRegisterInstruction).let { + it.registerC to it.registerE + } + seekbarMethod.addInstruction( + drawSegmentInstructionInsertIndex - 1, + "invoke-static {v$canvasInstance, v$centerY}, Lapp/revanced/integrations/sponsorblock/PlayerController;->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V" + ) + + /* + Set video length + */ + VideoLengthFingerprint.resolve(data, seekbarSignatureResult.classDef) + val videoLengthMethodResult = VideoLengthFingerprint.result!! + val videoLengthMethod = videoLengthMethodResult.mutableMethod + val videoLengthMethodInstructions = videoLengthMethod.implementation!!.instructions + + val videoLengthRegister = + (videoLengthMethodInstructions[videoLengthMethodResult.patternScanResult!!.endIndex - 2] as OneRegisterInstruction).registerA + val dummyRegisterForLong = + videoLengthRegister + 1 // this is required for long values since they are 64 bit wide + videoLengthMethod.addInstruction( + videoLengthMethodResult.patternScanResult!!.endIndex, + "invoke-static {v$videoLengthRegister, v$dummyRegisterForLong}, Lapp/revanced/integrations/sponsorblock/PlayerController;->setVideoLength(J)V" + ) + + /* + Voting & Shield button + */ + ShowPlayerControlsFingerprint.resolve(data, data.classes.find { it.type.endsWith("YouTubeControlsOverlay;") }!!) + val controlsMethodResult = ShowPlayerControlsFingerprint.result!! + + val controlsLayoutStubResourceId = + ResourceIdMappingProviderResourcePatch.resourceMappings.single { it.type == "id" && it.name == "controls_layout_stub" }.id + val zoomOverlayResourceId = + ResourceIdMappingProviderResourcePatch.resourceMappings.single { it.type == "id" && it.name == "video_zoom_overlay_stub" }.id + + methods@ for (method in controlsMethodResult.mutableClass.methods) { + val instructions = method.implementation?.instructions!! + instructions@ for ((index, instruction) in instructions.withIndex()) { + // search for method which inflates the controls layout view + if (instruction.opcode != Opcode.CONST) continue@instructions + + when ((instruction as NarrowLiteralInstruction).wideLiteral) { + controlsLayoutStubResourceId -> { + // replace the view with the YouTubeControlsOverlay + val moveResultInstructionIndex = index + 5 + val inflatedViewRegister = + (instructions[moveResultInstructionIndex] as OneRegisterInstruction).registerA + // initialize with the player overlay object + method.addInstructions( + moveResultInstructionIndex + 1, // insert right after moving the view to the register and use that register + """ + invoke-static {v$inflatedViewRegister}, Lapp/revanced/integrations/sponsorblock/ShieldButton;->initialize(Ljava/lang/Object;)V + invoke-static {v$inflatedViewRegister}, Lapp/revanced/integrations/sponsorblock/VotingButton;->initialize(Ljava/lang/Object;)V + """ + ) + } + + zoomOverlayResourceId -> { + val invertVisibilityMethod = + data.toMethodWalker(method).nextMethod(index - 6, true).getMethod() as MutableMethod + // change visibility of the buttons + invertVisibilityMethod.addInstructions( + 0, """ + invoke-static {p1}, Lapp/revanced/integrations/sponsorblock/ShieldButton;->changeVisibilityNegatedImmediate(Z)V + invoke-static {p1}, Lapp/revanced/integrations/sponsorblock/VotingButton;->changeVisibilityNegatedImmediate(Z)V + """.trimIndent() + ) + } + } + } + } + + // change visibility of the buttons + controlsMethodResult.mutableMethod.addInstructions( + 0, """ + invoke-static {p1}, Lapp/revanced/integrations/sponsorblock/ShieldButton;->changeVisibility(Z)V + invoke-static {p1}, Lapp/revanced/integrations/sponsorblock/VotingButton;->changeVisibility(Z)V + """.trimIndent() + ) + + // set SegmentHelperLayout.context to the player layout instance + val instanceRegister = 0 + NextGenWatchLayoutFingerprint.result!!.mutableMethod.addInstruction( + 3, // after super call + "invoke-static/range {p$instanceRegister}, Lapp/revanced/integrations/sponsorblock/PlayerController;->addSkipSponsorView15(Landroid/view/View;)V" + ) + + // append the new time to the player layout + val appendTimeFingerprintResult = AppendTimeFingerprint.result!! + val appendTimePatternScanStartIndex = appendTimeFingerprintResult.patternScanResult!!.startIndex + val targetRegister = + (appendTimeFingerprintResult.method.implementation!!.instructions.elementAt(appendTimePatternScanStartIndex + 1) as OneRegisterInstruction).registerA + + appendTimeFingerprintResult.mutableMethod.addInstructions( + appendTimePatternScanStartIndex + 2, """ + invoke-static {v$targetRegister}, Lapp/revanced/integrations/sponsorblock/SponsorBlockUtils;->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$targetRegister + """ + ) + + // initialize the player controller + val initFingerprintResult = PlayerInitFingerprint.result!! + val initInstanceRegister = 0 + initFingerprintResult.mutableClass.methods.first { MethodUtil.isConstructor(it) }.addInstruction( + 4, // after super class invoke + "invoke-static {v$initInstanceRegister}, Lapp/revanced/integrations/sponsorblock/PlayerController;->onCreate(Ljava/lang/Object;)V" + ) + + // initialize the sponsorblock view + PlayerOverlaysLayoutInitFingerprint.result!!.mutableMethod.addInstruction( + 6, // after inflating the view + "invoke-static {p0}, Lapp/revanced/integrations/sponsorblock/player/ui/SponsorBlockView;->initialize(Ljava/lang/Object;)V" + ) + + // lastly create hooks for the player controller + + // get original seek method + SeekFingerprint.resolve(data, initFingerprintResult.classDef) + val seekFingerprintResultMethod = SeekFingerprint.result!!.method + // get enum type for the seek helper method + val seekSourceEnumType = seekFingerprintResultMethod.parameterTypes[1].toString() + + // create helper method + val seekHelperMethod = ImmutableMethod( + seekFingerprintResultMethod.definingClass, + "seekHelper", + listOf(ImmutableMethodParameter("J", null, "time")), + "Z", + AccessFlags.PUBLIC or AccessFlags.FINAL, + null, null, + MutableMethodImplementation(4) + ).toMutable() + + // insert helper method instructions + seekHelperMethod.addInstructions( + 0, + """ + sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType + invoke-virtual {p0, p1, p2, v0}, ${seekFingerprintResultMethod.definingClass}->${seekFingerprintResultMethod.name}(J$seekSourceEnumType)Z + move-result p1 + return p1 + """ + ) + + // add the helper method to the original class + initFingerprintResult.mutableClass.methods.add(seekHelperMethod) + + // get rectangle field name + RectangleFieldInvalidatorFingerprint.resolve(data, seekbarSignatureResult.classDef) + val rectangleFieldInvalidatorInstructions = + RectangleFieldInvalidatorFingerprint.result!!.method.implementation!!.instructions + val rectangleFieldName = + ((rectangleFieldInvalidatorInstructions.elementAt(rectangleFieldInvalidatorInstructions.count() - 3) as ReferenceInstruction).reference as FieldReference).name + + // get the player controller class from the integrations + val playerControllerMethods = + data.proxy(data.classes.first { it.type.endsWith("PlayerController;") }).resolve().methods + + // get the method which contain the "replaceMe" strings + val replaceMeMethods = + playerControllerMethods.filter { it.name == "onCreate" || it.name == "setSponsorBarRect" } + + fun MutableMethod.replaceStringInstruction(index: Int, instruction: Instruction, with: String) { + val register = (instruction as OneRegisterInstruction).registerA + this.replaceInstruction( + index, "const-string v$register, \"$with\"" + ) + } + + // replace the "replaceMeWith*" strings + for (method in replaceMeMethods) { + for ((index, it) in method.implementation!!.instructions.withIndex()) { + if (it.opcode.ordinal != Opcode.CONST_STRING.ordinal) continue + + when (((it as ReferenceInstruction).reference as StringReference).string) { + "replaceMeWithsetSponsorBarRect" -> + method.replaceStringInstruction(index, it, rectangleFieldName) + + "replaceMeWithsetMillisecondMethod" -> + method.replaceStringInstruction(index, it, "seekHelper") + } + } + } + + // TODO: isSBChannelWhitelisting implementation + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt new file mode 100644 index 000000000..f552b91ed --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt @@ -0,0 +1,128 @@ +package app.revanced.patches.youtube.layout.sponsorblock.resource.patch + +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.Dependencies +import app.revanced.patcher.patch.impl.ResourcePatch +import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility +import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch +import java.io.OutputStream +import java.nio.file.Files + +@Name("sponsorblock-resource-patch") +@SponsorBlockCompatibility +@Dependencies([FixLocaleConfigErrorPatch::class]) +@Version("0.0.1") +class SponsorBlockResourcePatch : ResourcePatch() { + override fun execute(data: ResourceData): PatchResult { + val classLoader = this.javaClass.classLoader + + /* + merge SponsorBlock strings to main strings + */ + val stringsResourcePath = "values/strings.xml" + val stringsResourceInputStream = classLoader.getResourceAsStream("sponsorblock/$stringsResourcePath")!! + + // copy nodes from the resources node to the real resource node + "resources".copyXmlNode( + data.xmlEditor[stringsResourceInputStream, OutputStream.nullOutputStream()], + data.xmlEditor["res/$stringsResourcePath"] + ).close() // close afterwards + + /* + merge SponsorBlock drawables to main drawables + */ + val drawables = "drawable" to arrayOf( + "ic_sb_adjust", + "ic_sb_compare", + "ic_sb_edit", + "ic_sb_logo", + "ic_sb_publish", + "ic_sb_voting" + ) + + val layouts = "layout" to arrayOf( + "inline_sponsor_overlay", "new_segment", "skip_sponsor_button" + ) + + // collect resources + val xmlResources = arrayOf(drawables, layouts) + + // write resources + xmlResources.forEach { (path, resourceNames) -> + resourceNames.forEach { name -> + val relativePath = "$path/$name.xml" + + Files.copy( + classLoader.getResourceAsStream("sponsorblock/$relativePath")!!, + data["res"].resolve(relativePath).toPath() + ) + } + } + + /* + merge xml nodes from the host to their real xml files + */ + + // collect all host resources + val hostingXmlResources = mapOf("layout" to arrayOf("youtube_controls_layout")) + + // copy nodes from host resources to their real xml files + hostingXmlResources.forEach { (path, resources) -> + resources.forEach { resource -> + val hostingResourceStream = classLoader.getResourceAsStream("sponsorblock/host/$path/$resource.xml")!! + + val targetXmlEditor = data.xmlEditor["res/$path/$resource.xml"] + "RelativeLayout".copyXmlNode( + data.xmlEditor[hostingResourceStream, OutputStream.nullOutputStream()], + targetXmlEditor + ).also { + val children = targetXmlEditor.file.getElementsByTagName("RelativeLayout").item(0).childNodes + + // Replace the startOf with the voting button view so that the button does not overlap + for (i in 1 until children.length) { + val view = children.item(i) + + // Replace the attribute for a specific node only + if (!view.attributes.getNamedItem("android:id").nodeValue.endsWith("live_chat_overlay_button")) continue + + // voting button id from the voting button view from the youtube_controls_layout.xml host file + val votingButtonId = "@+id/voting_button" + + view.attributes.getNamedItem("android:layout_toStartOf").nodeValue = votingButtonId + + break + } + }.close() // close afterwards + } + } + return PatchResultSuccess() + } + + /** + * Copies the specified node of the source [DomFileEditor] to the target [DomFileEditor]. + * @param source the source [DomFileEditor]. + * @param target the target [DomFileEditor]- + */ + private fun String.copyXmlNode(source: DomFileEditor, target: DomFileEditor): AutoCloseable { + val hostNodes = source.file.getElementsByTagName(this).item(0).childNodes + + val destinationResourceFile = target.file + val destinationNode = destinationResourceFile.getElementsByTagName(this).item(0) + + for (index in 0 until hostNodes.length) { + val node = hostNodes.item(index).cloneNode(true) + destinationResourceFile.adoptNode(node) + destinationNode.appendChild(node) + } + + return AutoCloseable { + source.close() + target.close() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt index 1057da4be..c7ecc6e8d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt @@ -5,14 +5,16 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.impl.BytecodeData import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.Dependencies import app.revanced.patcher.patch.impl.BytecodePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.videoid.annotation.VideoIdCompatibility import app.revanced.patches.youtube.misc.videoid.fingerprint.VideoIdFingerprint -import org.jf.dexlib2.iface.instruction.formats.Instruction11x +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction @Name("video-id-hook") @Description("hook to detect when the video id changes") @@ -25,12 +27,21 @@ class VideoIdPatch : BytecodePatch( ) ) { override fun execute(data: BytecodeData): PatchResult { + result = VideoIdFingerprint.result!! + + insertMethod = result.mutableMethod + videoIdRegister = + (insertMethod.implementation!!.instructions[result.patternScanResult!!.endIndex + 1] as OneRegisterInstruction).registerA + injectCall("Lapp/revanced/integrations/videoplayer/VideoInformation;->setCurrentVideoId(Ljava/lang/String;)V") return PatchResultSuccess() } companion object { + private lateinit var result: MethodFingerprintResult + private var videoIdRegister: Int = 0 + private lateinit var insertMethod: MutableMethod private var offset = 2 /** @@ -40,12 +51,7 @@ class VideoIdPatch : BytecodePatch( fun injectCall( methodDescriptor: String ) { - val result = VideoIdFingerprint.result!! - - val method = result.mutableMethod - val videoIdRegister = - (method.implementation!!.instructions[result.patternScanResult!!.endIndex + 1] as Instruction11x).registerA - method.addInstructions( + insertMethod.addInstructions( result.patternScanResult!!.endIndex + offset, // after the move-result-object "invoke-static {v$videoIdRegister}, $methodDescriptor" ) diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_adjust.xml b/src/main/resources/sponsorblock/drawable/ic_sb_adjust.xml new file mode 100644 index 000000000..76a4b8bc9 --- /dev/null +++ b/src/main/resources/sponsorblock/drawable/ic_sb_adjust.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_compare.xml b/src/main/resources/sponsorblock/drawable/ic_sb_compare.xml new file mode 100644 index 000000000..04cc65e40 --- /dev/null +++ b/src/main/resources/sponsorblock/drawable/ic_sb_compare.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_edit.xml b/src/main/resources/sponsorblock/drawable/ic_sb_edit.xml new file mode 100644 index 000000000..e93574bd9 --- /dev/null +++ b/src/main/resources/sponsorblock/drawable/ic_sb_edit.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_logo.xml b/src/main/resources/sponsorblock/drawable/ic_sb_logo.xml new file mode 100644 index 000000000..c39b9e0b8 --- /dev/null +++ b/src/main/resources/sponsorblock/drawable/ic_sb_logo.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_publish.xml b/src/main/resources/sponsorblock/drawable/ic_sb_publish.xml new file mode 100644 index 000000000..de4e58d3a --- /dev/null +++ b/src/main/resources/sponsorblock/drawable/ic_sb_publish.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_voting.xml b/src/main/resources/sponsorblock/drawable/ic_sb_voting.xml new file mode 100644 index 000000000..97db9c98d --- /dev/null +++ b/src/main/resources/sponsorblock/drawable/ic_sb_voting.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml b/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml new file mode 100644 index 000000000..97796266a --- /dev/null +++ b/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml b/src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml new file mode 100644 index 000000000..6bc670fb9 --- /dev/null +++ b/src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/sponsorblock/layout/new_segment.xml b/src/main/resources/sponsorblock/layout/new_segment.xml new file mode 100644 index 000000000..155907c96 --- /dev/null +++ b/src/main/resources/sponsorblock/layout/new_segment.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/sponsorblock/layout/skip_sponsor_button.xml b/src/main/resources/sponsorblock/layout/skip_sponsor_button.xml new file mode 100644 index 000000000..3ceb8c362 --- /dev/null +++ b/src/main/resources/sponsorblock/layout/skip_sponsor_button.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/sponsorblock/values/strings.xml b/src/main/resources/sponsorblock/values/strings.xml new file mode 100644 index 000000000..03ffa545a --- /dev/null +++ b/src/main/resources/sponsorblock/values/strings.xml @@ -0,0 +1,182 @@ + + + Enable SponsorBlock + SponsorBlock is a crowd-sourced system for skipping annoying parts in YouTube videos + Enable new segment adding + Switch this on to enable experimental segment adding (has button visibility issues) + What to do with different segments + General + Show a toast when skipping segment automatically + Click to see an example toast + Skip count tracking + This lets SponsorBlock leaderboard system know how much time people have saved. The extension sends a message to the server each time you skip a segment + Adjusting new segment step + This is the number of milliseconds you can move when you use the time adjustment buttons while adding new segment + Minimum segment duration + Segments shorter than the set value (in seconds) will not be skipped or shown in the player + Your unique user id + This should be kept private. This is like a password and should not be shared with anyone. If someone has this, they can impersonate you + Import/Export settings + This is your entire configuration that is applicable in the desktop extension in JSON. This includes your userID, so be sure to share this wisely. + Change API URL + The address SponsorBlock uses to make calls to the server. <b>Don\'t change this unless you know what you\'re doing.</b> + Settings were successfully imported + Failed to import settings + Failed to export settings + Cache segments locally + Frequently watched videos (eg. music videos) may store segments in app cache to make skipping segments faster + Clear SponsorBlock segments cache + Sponsor + Paid promotion, paid referrals and direct advertisements + Intermission/Intro Animation + An interval without actual content. Could be a pause, static frame, repeating animation + Endcards/Credits + Credits or when the YouTube endcards appear. Not for spoken conclusions + Interaction Reminder (Subscribe) + When there is a short reminder to like, subscribe or follow them in the middle of content + Unpaid/Self Promotion + When there is unpaid or self promotion. This includes specific sections about merchandise, donations, or information about who they collaborated with + Music: Non-Music Section + Only for use in music videos. This includes introductions or outros in music videos + Filler Tangent/Jokes + Tangential scenes added only for filler or humor that are not required to understand the main content of the video. This should not include context or background details + Skipped a sponsor segment + Skipped sponsor + Skipped intro + Skipped outro + Skipped annoying reminder + Skipped self promotion + Skipped a non-music section + Skipped preview + Skipped filler + Skipped unsubmitted segment + Skip automatically + Show a skip button + Don\'t do anything + Skip segment + About + This app uses the API from SponsorBlock + Tap to learn more, and see downloads for other platforms at: sponsor.ajay.app + Integration made by JakubWeg + Tap to skip + + Unable to submit segments: Status: %d %s + Can\'t submit the segment.\nRate Limited (Too many from the same user or IP) + Can\'t submit the segment.\n\n%s + Can\'t submit the segment.\nAlready exists + Segment submitted successfully + Submitting segment… + + Unable to vote for segment: Status: %d %s + Can\'t vote for segment.\nRate Limited (Too many from the same user or IP) + Can\'t vote for segment.\n\n%s + Voted successfully + Voting for segment… + Upvote + Downvote + Change category + There are no segments to vote for + Enable voting + Switch this on to enable voting. + + Choose the segment category + You\'ve disabled this category in the settings, enable it to be able to submit + New SponsorBlock segment + Set %02d:%02d:%04d as the start or end of a new segment? + start + end + now + Time the segment begins at + Time the segment ends at + Beginning of segment set + End of segment set + Are the times correct? + The segment lasts from %02d:%02d to %02d:%02d (%d minutes %02d seconds)\nIs it ready to submit? + Mark two locations on the time bar first + Edit timing of segment manually + Do you want to edit the timing for the start or end of the segment? + Done + Invalid time given + + View guidelines + Guidelines contain tips and rules about submitting segments + There are guidelines + It\'s recommended to read the SponsorBlock guidelines before submitting any segment + Already read + Show me + + SponsorBlock settings + Uses the sponsor.ajay.app API + + Notification settings + "1. Google device registration and Cloud Messaging need to be enabled for notifications. +2. ReVanced needs to be shown as registered under Cloud Messaging. +3. Current State in Cloud Messaging must be Connected." + MicroG settings + ReVanced settings + + Seekbar Tapping + Seekbar Tapping (video progress bar) is disabled + Seekbar Tapping (video progress bar) is enabled + Normal + + Shorts Shelf + Shorts Shelf removal is turned off + Shorts Shelf removal is turned on + + Create Button has default visibility + Create Button is forcefully disabled + Create Button + + Community Guidelines + Community Guidelines removal is turned off + Community Guidelines removal is turned on + + Copy Link Button is hidden from the player overlay + Copy Link Button is shown in the player overlay + Copy Link Button With Timestamp is hidden from the player overlay + Copy Link Button With Timestamp is shown in the player overlay + Copy Link Button With Timestamp + Copy Link Button + + Quality Settings style + Using default style video quality settings + Using old style video quality settings + + Show time without segments + This time appears in brackets next to the current time. This shows the total video duration minus any segments. + Channel whitelisting + Use the Segments button under the player to whitelist a channel + Enable SB Browser button + Clicking this button under the player will open sb.ltn.fi where you can see all the segments on the video. + Preview/Recap + Recap of previous episodes, or a preview of what\'s coming up later in the current video or future videos in the same series. Intended for edited together clips that do not provide additional information. + Stats + Loading.. + SponsorBlock is disabled + Your username: <b>%s</b> + Click to change your username + Unable to change username: Status: %d %s + Username successfully changed + Submissions: <b>%s</b> + You\'ve saved people from <b>%s</b> segments. + That\'s <b>%s</b> of their lives. Click to see the leaderboard + You\'ve skipped <b>%s</b> segments. + That\'s <b>%s</b>. + minutes + Are you looking for changing colors? + You can now change a category\'s color by clicking on it above. + Choose the category + Color changed + Color reset + Invalid hex code + Change + Reset + + Segments + SB Browser + + API URL changed + API URL reset + Provided API URL is invalid +