Compare commits

...

22 Commits

Author SHA1 Message Date
semantic-release-bot
9acf15f571 chore(release): 4.0.0-dev.11 [skip ci]
# [4.0.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.10...v4.0.0-dev.11) (2024-01-17)

### Features

* **YouTube:** Support version `19.02.34` ([#2627](https://github.com/ReVanced/revanced-patches/issues/2627)) ([126fe48](126fe48ce6))
2024-01-17 20:27:00 +00:00
LisoUseInAIKyrios
126fe48ce6 feat(YouTube): Support version 19.02.34 (#2627) 2024-01-18 00:24:55 +04:00
semantic-release-bot
32d2037083 chore(release): 4.0.0-dev.10 [skip ci]
# [4.0.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.9...v4.0.0-dev.10) (2024-01-16)

### Features

* **YouTube:** Support versions `18.48.39`, `18.49.37` and `19.01.34` ([#2551](https://github.com/ReVanced/revanced-patches/issues/2551)) ([aca1dd6](aca1dd6074))
2024-01-16 18:56:13 +00:00
oSumAtrIX
aca1dd6074 feat(YouTube): Support versions 18.48.39, 18.49.37 and 19.01.34 (#2551)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2024-01-16 19:54:06 +01:00
semantic-release-bot
30c6749f61 chore(release): 4.0.0-dev.9 [skip ci]
# [4.0.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.8...v4.0.0-dev.9) (2024-01-11)

### Bug Fixes

* **YouTube - Enable slide to seek:** Change patch default to excluded and add description disclaimer ([#2610](https://github.com/ReVanced/revanced-patches/issues/2610)) ([08c3079](08c30791ae))
2024-01-11 14:56:11 +00:00
LisoUseInAIKyrios
08c30791ae fix(YouTube - Enable slide to seek): Change patch default to excluded and add description disclaimer (#2610) 2024-01-11 15:54:10 +01:00
semantic-release-bot
002f11a854 chore(release): 4.0.0-dev.8 [skip ci]
# [4.0.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.7...v4.0.0-dev.8) (2024-01-10)

### Bug Fixes

* **YouTube:** Shorten setting titles to fit on screen ([#2579](https://github.com/ReVanced/revanced-patches/issues/2579)) ([861e9a3](861e9a399e))
2024-01-10 11:28:55 +00:00
KobeW50
861e9a399e fix(YouTube): Shorten setting titles to fit on screen (#2579) 2024-01-10 15:26:24 +04:00
oSumAtrIX
795aee13e4 build: Bump dependencies 2024-01-10 09:33:02 +01:00
semantic-release-bot
09f29e6119 chore(release): 4.0.0-dev.7 [skip ci]
# [4.0.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.6...v4.0.0-dev.7) (2024-01-10)

### Bug Fixes

* Use new integrations patch path ([784aa2f](784aa2f246))
2024-01-10 08:16:50 +00:00
oSumAtrIX
784aa2f246 fix: Use new integrations patch path 2024-01-10 09:14:12 +01:00
oSumAtrIX
4ddd5a0b8f chore: Update CI dependencies 2024-01-09 20:14:14 +01:00
semantic-release-bot
1482e7e1e8 chore(release): 4.0.0-dev.6 [skip ci]
# [4.0.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.5...v4.0.0-dev.6) (2024-01-09)

### Features

* **Tiktok - Playback speed:** Remember playback speed ([#2506](https://github.com/ReVanced/revanced-patches/issues/2506)) ([806e944](806e94481c))
2024-01-09 19:12:34 +00:00
d4rkk3y
806e94481c feat(Tiktok - Playback speed): Remember playback speed (#2506)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-01-09 20:10:29 +01:00
semantic-release-bot
edcb6eac6d chore(release): 4.0.0-dev.5 [skip ci]
# [4.0.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.4...v4.0.0-dev.5) (2024-01-09)

### Bug Fixes

* **YouTube - Change header:** Improve patch descriptions ([#2581](https://github.com/ReVanced/revanced-patches/issues/2581)) ([62c9085](62c9085096))
2024-01-09 19:09:58 +00:00
LisoUseInAIKyrios
4dced95d54 refactor(YouTube - Return YouTube Dislike): Make patch more robust by removing opcode patterns from fingerprints (#2602) 2024-01-09 23:08:01 +04:00
KobeW50
62c9085096 fix(YouTube - Change header): Improve patch descriptions (#2581) 2024-01-09 20:07:11 +01:00
semantic-release-bot
50a9f09703 chore(release): 4.0.0-dev.4 [skip ci]
# [4.0.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.3...v4.0.0-dev.4) (2024-01-09)

### Features

* **MyFitnessPal:** Add `Hide ads` patch ([#2594](https://github.com/ReVanced/revanced-patches/issues/2594)) ([9633b4e](9633b4eef0))
2024-01-09 17:28:21 +00:00
mrwedders
9633b4eef0 feat(MyFitnessPal): Add Hide ads patch (#2594)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-01-09 18:26:15 +01:00
semantic-release-bot
2a94ad681c chore(release): 4.0.0-dev.3 [skip ci]
# [4.0.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.2...v4.0.0-dev.3) (2024-01-09)

### Features

* **Change package name:** Mention caveat of the patch in the description ([9e79e9e](9e79e9e72c))
2024-01-09 15:41:21 +00:00
oSumAtrIX
9e79e9e72c feat(Change package name): Mention caveat of the patch in the description 2024-01-09 16:39:23 +01:00
LisoUseInAIKyrios
429badef1a fix:(YouTube - Spoof app version): Adjust spoof target description (#2578) 2024-01-03 19:14:32 +04:00
97 changed files with 5623 additions and 854 deletions

View File

@@ -1,3 +1,66 @@
# [4.0.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.10...v4.0.0-dev.11) (2024-01-17)
### Features
* **YouTube:** Support version `19.02.34` ([#2627](https://github.com/ReVanced/revanced-patches/issues/2627)) ([94e08b7](https://github.com/ReVanced/revanced-patches/commit/94e08b74ced394abf9ae7d4fe6355bfe4d0be248))
# [4.0.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.9...v4.0.0-dev.10) (2024-01-16)
### Features
* **YouTube:** Support versions `18.48.39`, `18.49.37` and `19.01.34` ([#2551](https://github.com/ReVanced/revanced-patches/issues/2551)) ([a938e73](https://github.com/ReVanced/revanced-patches/commit/a938e736fa2aed1792cfdce5656efa15d0791d71))
# [4.0.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.8...v4.0.0-dev.9) (2024-01-11)
### Bug Fixes
* **YouTube - Enable slide to seek:** Change patch default to excluded and add description disclaimer ([#2610](https://github.com/ReVanced/revanced-patches/issues/2610)) ([2fdc4c2](https://github.com/ReVanced/revanced-patches/commit/2fdc4c23b5f39153ad71071359274c39129d691f))
# [4.0.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.7...v4.0.0-dev.8) (2024-01-10)
### Bug Fixes
* **YouTube:** Shorten setting titles to fit on screen ([#2579](https://github.com/ReVanced/revanced-patches/issues/2579)) ([b2a5dd3](https://github.com/ReVanced/revanced-patches/commit/b2a5dd3efc39ae8a42159858b9c00b5b2f8655a4))
# [4.0.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.6...v4.0.0-dev.7) (2024-01-10)
### Bug Fixes
* Use new integrations patch path ([51e2f3b](https://github.com/ReVanced/revanced-patches/commit/51e2f3b476b49460e2f3fc2b5f302a3a72d7963f))
# [4.0.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.5...v4.0.0-dev.6) (2024-01-09)
### Features
* **Tiktok - Playback speed:** Remember playback speed ([#2506](https://github.com/ReVanced/revanced-patches/issues/2506)) ([d2970e5](https://github.com/ReVanced/revanced-patches/commit/d2970e54fbbd7e4b1ae1d354ae2d5c4bbe9336b0))
# [4.0.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.4...v4.0.0-dev.5) (2024-01-09)
### Bug Fixes
* **YouTube - Change header:** Improve patch descriptions ([#2581](https://github.com/ReVanced/revanced-patches/issues/2581)) ([43a5677](https://github.com/ReVanced/revanced-patches/commit/43a5677397380f14a049ae95532fd5096b94c938))
# [4.0.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.3...v4.0.0-dev.4) (2024-01-09)
### Features
* **MyFitnessPal:** Add `Hide ads` patch ([#2594](https://github.com/ReVanced/revanced-patches/issues/2594)) ([fd4b3c7](https://github.com/ReVanced/revanced-patches/commit/fd4b3c79a83f8de6256611629263d3e29e66f2c2))
# [4.0.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.2...v4.0.0-dev.3) (2024-01-09)
### Features
* **Change package name:** Mention caveat of the patch in the description ([427b81a](https://github.com/ReVanced/revanced-patches/commit/427b81a79a5a1de79f14d2261059fb098b22227f))
# [4.0.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.1...v4.0.0-dev.2) (2024-01-02) # [4.0.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.1...v4.0.0-dev.2) (2024-01-02)

View File

@@ -333,6 +333,20 @@ public final class app/revanced/patches/myexpenses/misc/pro/UnlockProPatch : app
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
} }
public final class app/revanced/patches/myfitnesspal/ads/HideAdsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/myfitnesspal/ads/HideAdsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/myfitnesspal/ads/fingerprints/IsPremiumUseCaseImplFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint {
public static final field INSTANCE Lapp/revanced/patches/myfitnesspal/ads/fingerprints/IsPremiumUseCaseImplFingerprint;
}
public final class app/revanced/patches/myfitnesspal/ads/fingerprints/MainActivityNavigateToNativePremiumUpsellFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint {
public static final field INSTANCE Lapp/revanced/patches/myfitnesspal/ads/fingerprints/MainActivityNavigateToNativePremiumUpsellFingerprint;
}
public final class app/revanced/patches/netguard/broadcasts/removerestriction/RemoveBroadcastsRestrictionPatch : app/revanced/patcher/patch/ResourcePatch { public final class app/revanced/patches/netguard/broadcasts/removerestriction/RemoveBroadcastsRestrictionPatch : app/revanced/patcher/patch/ResourcePatch {
public static final field INSTANCE Lapp/revanced/patches/netguard/broadcasts/removerestriction/RemoveBroadcastsRestrictionPatch; public static final field INSTANCE Lapp/revanced/patches/netguard/broadcasts/removerestriction/RemoveBroadcastsRestrictionPatch;
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V

View File

@@ -1,4 +1,4 @@
org.gradle.parallel = true org.gradle.parallel = true
org.gradle.caching = true org.gradle.caching = true
kotlin.code.style = official kotlin.code.style = official
version = 4.0.0-dev.2 version = 4.0.0-dev.11

View File

@@ -1,5 +1,5 @@
[versions] [versions]
revanced-patcher = "19.1.0" revanced-patcher = "19.2.0"
smali = "3.0.3" smali = "3.0.3"
guava = "33.0.0-jre" guava = "33.0.0-jre"
gson = "2.10.1" gson = "2.10.1"

5045
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
"@saithodev/semantic-release-backmerge": "^4.0.1", "@saithodev/semantic-release-backmerge": "^4.0.1",
"@semantic-release/changelog": "^6.0.3", "@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1", "@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.8.0", "gradle-semantic-release-plugin": "^1.9.0",
"semantic-release": "^22.0.12" "semantic-release": "^22.0.12"
} }
} }

File diff suppressed because one or more lines are too long

View File

@@ -10,7 +10,7 @@ import java.io.Closeable
@Patch( @Patch(
name = "Change package name", name = "Change package name",
description = "Appends \".revanced\" to the package name by default.", description = "Appends \".revanced\" to the package name by default. Changing the package name of the app can lead to unexpected issues.",
use = false use = false
) )
@Suppress("unused") @Suppress("unused")
@@ -59,4 +59,4 @@ object ChangePackageNamePatch : ResourcePatch(), Closeable {
manifest.setAttribute("package", replacementPackageName) manifest.setAttribute("package", replacementPackageName)
} }
} }

View File

@@ -10,7 +10,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.Instruction
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
abstract class AbstractTransformInstructionsPatch<T> : BytecodePatch() { abstract class AbstractTransformInstructionsPatch<T> : BytecodePatch() {
abstract fun filterMap( abstract fun filterMap(
classDef: ClassDef, classDef: ClassDef,
method: Method, method: Method,

View File

@@ -0,0 +1,38 @@
package app.revanced.patches.myfitnesspal.ads
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.myfitnesspal.ads.fingerprints.IsPremiumUseCaseImplFingerprint
import app.revanced.patches.myfitnesspal.ads.fingerprints.MainActivityNavigateToNativePremiumUpsellFingerprint
import app.revanced.util.exception
@Patch(
name = "Hide ads",
description = "Hides most of the ads across the app.",
compatiblePackages = [CompatiblePackage("com.myfitnesspal.android")]
)
@Suppress("unused")
object HideAdsPatch : BytecodePatch(
setOf(IsPremiumUseCaseImplFingerprint, MainActivityNavigateToNativePremiumUpsellFingerprint)
) {
override fun execute(context: BytecodeContext) {
// Overwrite the premium status specifically for ads.
IsPremiumUseCaseImplFingerprint.result?.mutableMethod?.replaceInstructions(
0,
"""
sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;
return-object v0
"""
) ?: throw IsPremiumUseCaseImplFingerprint.exception
// Prevent the premium upsell dialog from showing when the main activity is launched.
// In other places that are premium-only the dialog will still show.
MainActivityNavigateToNativePremiumUpsellFingerprint.result?.mutableMethod?.replaceInstructions(
0,
"return-void"
) ?: throw MainActivityNavigateToNativePremiumUpsellFingerprint.exception
}
}

View File

@@ -0,0 +1,11 @@
package app.revanced.patches.myfitnesspal.ads.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
object IsPremiumUseCaseImplFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC.value,
customFingerprint = { methodDef, classDef ->
classDef.type.endsWith("IsPremiumUseCaseImpl;") && methodDef.name == "doWork"
}
)

View File

@@ -0,0 +1,13 @@
package app.revanced.patches.myfitnesspal.ads.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
object MainActivityNavigateToNativePremiumUpsellFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
customFingerprint = { methodDef, classDef ->
classDef.type.endsWith("MainActivity;") && methodDef.name == "navigateToNativePremiumUpsell"
}
)

View File

@@ -1,49 +1,82 @@
package app.revanced.patches.tiktok.interaction.speed package app.revanced.patches.tiktok.interaction.speed
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.tiktok.interaction.speed.fingerprints.GetSpeedFingerprint
import app.revanced.patches.tiktok.interaction.speed.fingerprints.SpeedControlParentFingerprint import app.revanced.patches.tiktok.interaction.speed.fingerprints.OnRenderFirstFrameFingerprint
import app.revanced.patches.tiktok.interaction.speed.fingerprints.SetSpeedFingerprint
import app.revanced.util.exception import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction11x
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Patch( @Patch(
name = "Playback speed", name = "Playback speed",
description = "Enables the playback speed option for all videos.", description = "Enables the playback speed option for all videos and " +
"retains the speed configurations in between videos.",
compatiblePackages = [ compatiblePackages = [
CompatiblePackage("com.ss.android.ugc.trill", ["32.5.3"]), CompatiblePackage("com.ss.android.ugc.trill", ["32.5.3"]),
CompatiblePackage("com.zhiliaoapp.musically", ["32.5.3"]) CompatiblePackage("com.zhiliaoapp.musically", ["32.5.3"])
] ]
) )
@Suppress("unused") @Suppress("unused")
object PlaybackSpeedPatch : BytecodePatch(setOf(SpeedControlParentFingerprint)) { object PlaybackSpeedPatch : BytecodePatch(
setOf(
GetSpeedFingerprint,
OnRenderFirstFrameFingerprint,
SetSpeedFingerprint
)
) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
SpeedControlParentFingerprint.result?.mutableMethod?.apply { SetSpeedFingerprint.result?.let { onVideoSwiped ->
val targetMethodCallIndex = indexOfFirstInstruction { // Remember the playback speed of the current video.
if (opcode == Opcode.INVOKE_STATIC) { GetSpeedFingerprint.result?.mutableMethod?.apply {
val paramsTypes = ((this as Instruction35c).reference as MethodReference).parameterTypes val injectIndex = indexOfFirstInstruction { getReference<MethodReference>()?.returnType == "F" } + 2
paramsTypes.size == 1 && paramsTypes[0].contains("/Aweme;") val register = getInstruction<Instruction11x>(injectIndex - 1).registerA
} else false
}
val isSpeedEnableMethod = context addInstruction(
.toMethodWalker(this) injectIndex,
.nextMethod(targetMethodCallIndex, true) "invoke-static { v$register }," +
.getMethod() as MutableMethod " Lapp/revanced/integrations/tiktok/speed/PlaybackSpeedPatch;->rememberPlaybackSpeed(F)V"
)
} ?: throw GetSpeedFingerprint.exception
isSpeedEnableMethod.addInstructions( // By default, the playback speed will reset to 1.0 at the start of each video.
// Instead, override it with the desired playback speed.
OnRenderFirstFrameFingerprint.result?.mutableMethod?.addInstructions(
0, 0,
""" """
const/4 v0, 0x1 # Video playback location (e.g. home page, following page or search result page) retrieved using getEnterFrom method.
return v0 const/4 v0, 0x1
invoke-virtual {p0, v0}, Lcom/ss/android/ugc/aweme/feed/panel/BaseListFragmentPanel;->getEnterFrom(Z)Ljava/lang/String;
move-result-object v0
# Model of current video retrieved using getCurrentAweme method.
invoke-virtual {p0}, Lcom/ss/android/ugc/aweme/feed/panel/BaseListFragmentPanel;->getCurrentAweme()Lcom/ss/android/ugc/aweme/feed/model/Aweme;
move-result-object v1
# Desired playback speed retrieved using getPlaybackSpeed method.
invoke-static {}, Lapp/revanced/integrations/tiktok/speed/PlaybackSpeedPatch;->getPlaybackSpeed()F
move-result-object v2
invoke-static { v0, v1, v2 }, ${onVideoSwiped.method}
"""
) ?: throw OnRenderFirstFrameFingerprint.exception
// Force enable the playback speed option for all videos.
onVideoSwiped.mutableClass.methods.find { method -> method.returnType == "Z" }?.addInstructions(
0,
""" """
) const/4 v0, 0x1
} ?: throw SpeedControlParentFingerprint.exception return v0
"""
) ?: throw PatchException("Failed to force enable the playback speed option.")
} ?: throw SetSpeedFingerprint.exception
} }
} }

View File

@@ -0,0 +1,9 @@
package app.revanced.patches.tiktok.interaction.speed.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object GetSpeedFingerprint : MethodFingerprint(
customFingerprint = { methodDef, _ ->
methodDef.definingClass.endsWith("/BaseListFragmentPanel;") && methodDef.name == "onFeedSpeedSelectedEvent"
}
)

View File

@@ -0,0 +1,9 @@
package app.revanced.patches.tiktok.interaction.speed.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object OnRenderFirstFrameFingerprint : MethodFingerprint(
customFingerprint = { methodDef, _ ->
methodDef.definingClass.endsWith("/BaseListFragmentPanel;") && methodDef.name == "onRenderFirstFrame"
}
)

View File

@@ -0,0 +1,16 @@
package app.revanced.patches.tiktok.interaction.speed.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object SetSpeedFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf(
"Ljava/lang/String;",
"Lcom/ss/android/ugc/aweme/feed/model/Aweme;",
"F"
),
strings = listOf("enterFrom")
)

View File

@@ -1,13 +0,0 @@
package app.revanced.patches.tiktok.interaction.speed.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object SpeedControlParentFingerprint : MethodFingerprint(
strings = listOf(
"onStopTrackingTouch, hasTouchMove=",
", isCurVideoPaused: ",
"already_shown_edge_speed_guide"
)
)

View File

@@ -24,15 +24,17 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
], ],
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube", "com.google.android.youtube", [
[
"18.32.39", "18.32.39",
"18.37.36", "18.37.36",
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -25,8 +25,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -29,8 +29,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -17,15 +17,11 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch
], ],
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube", "com.google.android.youtube", [
[ "18.48.39",
"18.32.39", "18.49.37",
"18.37.36", "19.01.34",
"18.38.44", "19.02.34"
"18.43.45",
"18.44.41",
"18.45.41",
"18.45.43"
] ]
) )
] ]

View File

@@ -21,7 +21,18 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
dependencies = [IntegrationsPatch::class, SettingsPatch::class], dependencies = [IntegrationsPatch::class, SettingsPatch::class],
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube" "com.google.android.youtube", [
"18.32.39",
"18.37.36",
"18.38.44",
"18.43.45",
"18.44.41",
"18.45.43",
"18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
]
) )
] ]
) )

View File

@@ -17,15 +17,11 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch
], ],
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube", "com.google.android.youtube", [
[ "18.48.39",
"18.32.39", "18.49.37",
"18.37.36", "19.01.34",
"18.38.44", "19.02.34"
"18.43.45",
"18.44.41",
"18.45.41",
"18.45.43"
] ]
), ),
] ]

View File

@@ -27,8 +27,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -29,8 +29,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
[ [
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -17,7 +17,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch( @Patch(
name = "Enable slide to seek", name = "Enable slide to seek",
description = "Adds an option to enable slide to seek instead of playing at 2x speed when pressing and holding in the video player.", description = "Adds an option to enable slide to seek instead of playing at 2x speed when pressing and holding in the video player. Including this patch may cause issues with tapping or double tapping the video player overlay.",
dependencies = [IntegrationsPatch::class, SettingsPatch::class], dependencies = [IntegrationsPatch::class, SettingsPatch::class],
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
@@ -25,11 +25,15 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
[ [
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ],
use = false
) )
@Suppress("unused") @Suppress("unused")
object EnableSlideToSeekPatch : BytecodePatch( object EnableSlideToSeekPatch : BytecodePatch(

View File

@@ -1,7 +1,5 @@
package app.revanced.patches.youtube.interaction.swipecontrols package app.revanced.patches.youtube.interaction.swipecontrols
import app.revanced.util.transformMethods
import app.revanced.util.traverseClassHierarchy
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
@@ -10,7 +8,9 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMu
import app.revanced.patches.youtube.interaction.swipecontrols.fingerprints.SwipeControlsHostActivityFingerprint import app.revanced.patches.youtube.interaction.swipecontrols.fingerprints.SwipeControlsHostActivityFingerprint
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.shared.fingerprints.WatchWhileActivityFingerprint import app.revanced.patches.youtube.shared.fingerprints.MainActivityFingerprint
import app.revanced.util.transformMethods
import app.revanced.util.traverseClassHierarchy
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
@@ -31,8 +31,11 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]
@@ -40,19 +43,19 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
@Suppress("unused") @Suppress("unused")
object SwipeControlsBytecodePatch : BytecodePatch( object SwipeControlsBytecodePatch : BytecodePatch(
setOf( setOf(
WatchWhileActivityFingerprint, MainActivityFingerprint,
SwipeControlsHostActivityFingerprint SwipeControlsHostActivityFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
val wrapperClass = SwipeControlsHostActivityFingerprint.result!!.mutableClass val wrapperClass = SwipeControlsHostActivityFingerprint.result!!.mutableClass
val targetClass = WatchWhileActivityFingerprint.result!!.mutableClass val targetClass = MainActivityFingerprint.result!!.mutableClass
// inject the wrapper class from integrations into the class hierarchy of WatchWhileActivity // Inject the wrapper class from integrations into the class hierarchy of MainActivity.
wrapperClass.setSuperClass(targetClass.superclass) wrapperClass.setSuperClass(targetClass.superclass)
targetClass.setSuperClass(wrapperClass.type) targetClass.setSuperClass(wrapperClass.type)
// ensure all classes and methods in the hierarchy are non-final, so we can override them in integrations // Ensure all classes and methods in the hierarchy are non-final, so we can override them in integrations.
context.traverseClassHierarchy(targetClass) { context.traverseClassHierarchy(targetClass) {
accessFlags = accessFlags and AccessFlags.FINAL.value.inv() accessFlags = accessFlags and AccessFlags.FINAL.value.inv()
transformMethods { transformMethods {

View File

@@ -29,8 +29,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
], ],

View File

@@ -12,7 +12,7 @@ import java.io.File
@Patch( @Patch(
name = "Change header", name = "Change header",
description = "Change the in app header. Defaults to the ReVanced header.", description = "Applies a custom header in the top left corner within the app. Defaults to the ReVanced header.",
compatiblePackages = [ compatiblePackages = [
CompatiblePackage("com.google.android.youtube") CompatiblePackage("com.google.android.youtube")
], ],
@@ -48,8 +48,8 @@ object ChangeHeaderPatch : ResourcePatch() {
), ),
title = "Header", title = "Header",
description = """ description = """
The header to use in top bar or the path to a custom header. Either a header name or a path to a custom header folder to use in the top bar.
The path to a folder containing one or more of the following folders matching the DPI of your device: The path to a folder must contain one or more of the following folders matching the DPI of your device:
${targetResourceDirectoryNames.joinToString("\n") { "- $it" }} ${targetResourceDirectoryNames.joinToString("\n") { "- $it" }}

View File

@@ -27,8 +27,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -37,8 +37,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -28,8 +28,11 @@ import com.android.tools.smali.dexlib2.Opcode
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -34,8 +34,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -32,8 +32,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -27,8 +27,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -27,8 +27,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -26,8 +26,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -27,8 +27,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -30,8 +30,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -27,8 +27,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -23,8 +23,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -23,8 +23,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -37,8 +37,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]
@@ -97,7 +100,7 @@ object HideLayoutComponentsPatch : BytecodePatch(
"revanced_hide_search_result_recommendations", "revanced_hide_search_result_recommendations",
StringResource( StringResource(
"revanced_hide_search_result_recommendations_title", "revanced_hide_search_result_recommendations_title",
"Hide search result recommendations (e.g People also watched)" "Hide \\\'People also watched\\\' recommendations"
), ),
StringResource( StringResource(
"revanced_hide_search_result_recommendations_summary_on", "revanced_hide_search_result_recommendations_summary_on",

View File

@@ -34,8 +34,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -23,8 +23,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -23,8 +23,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -20,15 +20,20 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
SettingsPatch::class SettingsPatch::class
], ],
compatiblePackages = [ compatiblePackages = [
CompatiblePackage("com.google.android.youtube", [ CompatiblePackage(
"18.32.39", "com.google.android.youtube", [
"18.37.36", "18.32.39",
"18.38.44", "18.37.36",
"18.43.45", "18.38.44",
"18.44.41", "18.43.45",
"18.45.41", "18.44.41",
"18.45.43" "18.45.43",
]) "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
]
)
] ]
) )
@Suppress("unused") @Suppress("unused")

View File

@@ -25,8 +25,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"com.google.android.youtube", [ "com.google.android.youtube", [
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -31,8 +31,11 @@ import app.revanced.patches.youtube.shared.fingerprints.SeekbarOnDrawFingerprint
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -35,8 +35,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -22,8 +22,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -19,13 +19,15 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube", [ "com.google.android.youtube", [
"18.32.39",
"18.37.36", "18.37.36",
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -24,8 +24,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -18,8 +18,11 @@ import org.w3c.dom.Element
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
], ],

View File

@@ -1,29 +1,45 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike package app.revanced.patches.youtube.layout.returnyoutubedislike
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.* import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.ConversionContextFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.DislikeFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.DislikesOldLayoutTextViewFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.LikeFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RemoveLikeFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberMeasureAnimatedTextFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberMeasureStaticLabelFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberMeasureStaticLabelParentFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberSetterFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberTextViewFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.ShortsTextViewFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentConstructorFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentDataFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentLookupFingerprint
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.shared.fingerprints.RollingNumberTextViewAnimationUpdateFingerprint import app.revanced.patches.youtube.shared.fingerprints.RollingNumberTextViewAnimationUpdateFingerprint
import app.revanced.patches.youtube.video.videoid.VideoIdPatch import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
@Patch( @Patch(
name = "Return YouTube Dislike", name = "Return YouTube Dislike",
@@ -38,10 +54,9 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube", [ "com.google.android.youtube", [
"18.43.45", "18.49.37",
"18.44.41", "19.01.34",
"18.45.41", "19.02.34"
"18.45.43"
] ]
) )
] ]
@@ -49,14 +64,17 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused") @Suppress("unused")
object ReturnYouTubeDislikePatch : BytecodePatch( object ReturnYouTubeDislikePatch : BytecodePatch(
setOf( setOf(
ConversionContextFingerprint,
TextComponentConstructorFingerprint, TextComponentConstructorFingerprint,
TextComponentDataFingerprint,
ShortsTextViewFingerprint, ShortsTextViewFingerprint,
DislikesOldLayoutTextViewFingerprint, DislikesOldLayoutTextViewFingerprint,
LikeFingerprint, LikeFingerprint,
DislikeFingerprint, DislikeFingerprint,
RemoveLikeFingerprint, RemoveLikeFingerprint,
RollingNumberSetterFingerprint, RollingNumberSetterFingerprint,
RollingNumberMeasureTextParentFingerprint, RollingNumberMeasureStaticLabelParentFingerprint,
RollingNumberMeasureAnimatedTextFingerprint,
RollingNumberTextViewFingerprint, RollingNumberTextViewFingerprint,
RollingNumberTextViewAnimationUpdateFingerprint RollingNumberTextViewAnimationUpdateFingerprint
) )
@@ -67,6 +85,8 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
private const val FILTER_CLASS_DESCRIPTOR = private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/components/ReturnYouTubeDislikeFilterPatch;" "Lapp/revanced/integrations/youtube/patches/components/ReturnYouTubeDislikeFilterPatch;"
private fun MethodFingerprint.resultOrThrow() = result ?: throw exception
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
// region Inject newVideoLoaded event handler to update dislikes when a new video is loaded. // region Inject newVideoLoaded event handler to update dislikes when a new video is loaded.
@@ -97,174 +117,54 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
// endregion // endregion
// region Hook creation of Spans and the cached lookup of them. // region Hook code for creation and cached lookup of text Spans.
// Alternatively the hook can be made at the creation of Spans in TextComponentSpec, // Alternatively the hook can be made at the creation of Spans in TextComponentSpec,
// And it works in all situations except it fails to update the Span when the user dislikes, // And it works in all situations except it fails to update the Span when the user dislikes,
// since the underlying (likes only) text did not change. // since the underlying (likes only) text did not change.
// This hook handles all situations, as it's where the created Spans are stored and later reused. // This hook handles all situations, as it's where the created Spans are stored and later reused.
TextComponentContextFingerprint.also { TextComponentConstructorFingerprint.result?.let { textConstructorResult ->
if (!it.resolve(context, TextComponentConstructorFingerprint.result!!.classDef)) // Find the field name of the conversion context.
throw it.exception val conversionContextClassType = ConversionContextFingerprint.resultOrThrow().classDef.type
}.result?.also { result -> val conversionContextField = textConstructorResult.classDef.fields.find {
if (!TextComponentAtomicReferenceFingerprint.resolve(context, result.method, result.classDef)) it.type == conversionContextClassType
throw TextComponentAtomicReferenceFingerprint.exception } ?: throw PatchException("Could not find conversion context field")
}?.let { textComponentContextFingerprintResult ->
val conversionContextIndex = textComponentContextFingerprintResult
.scanResult.patternScanResult!!.endIndex
val atomicReferenceStartIndex = TextComponentAtomicReferenceFingerprint.result!!
.scanResult.patternScanResult!!.startIndex
val insertIndex = atomicReferenceStartIndex + 9 TextComponentLookupFingerprint.resolve(context, textConstructorResult.classDef)
TextComponentLookupFingerprint.resultOrThrow().mutableMethod.apply {
// Find the instruction for creating the text data object.
val textDataClassType = TextComponentDataFingerprint.resultOrThrow().classDef.type
val insertIndex = indexOfFirstInstruction {
opcode == Opcode.NEW_INSTANCE &&
getReference<TypeReference>()?.type == textDataClassType
}
if (insertIndex < 0) throw PatchException("Could not find data creation instruction")
val tempRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
textComponentContextFingerprintResult.mutableMethod.apply { // Find the instruction that sets the span to an instance field.
// Get the conversion context obfuscated field name // The instruction is only a few lines after the creation of the instance.
val conversionContextFieldReference = // The method has multiple iput-object instructions using a CharSequence,
getInstruction<ReferenceInstruction>(conversionContextIndex).reference // so verify the found instruction is in the expected location.
val putFieldInstruction = implementation!!.instructions
// Free register to hold the conversion context .subList(insertIndex, insertIndex + 20)
val freeRegister = .find {
getInstruction<TwoRegisterInstruction>(atomicReferenceStartIndex).registerB it.opcode == Opcode.IPUT_OBJECT &&
it.getReference<FieldReference>()?.type == "Ljava/lang/CharSequence;"
val atomicReferenceRegister = } ?: throw PatchException("Could not find put object instruction")
getInstruction<FiveRegisterInstruction>(atomicReferenceStartIndex + 6).registerC val charSequenceRegister = (putFieldInstruction as TwoRegisterInstruction).registerA
// Instruction that is replaced, and also has the CharacterSequence register.
val moveCharSequenceInstruction = getInstruction<TwoRegisterInstruction>(insertIndex)
val charSequenceSourceRegister = moveCharSequenceInstruction.registerB
val charSequenceTargetRegister = moveCharSequenceInstruction.registerA
// Move the current instance to the free register, and get the conversion context from it.
// Must replace the instruction to preserve the control flow label.
replaceInstruction(insertIndex, "move-object/from16 v$freeRegister, p0")
addInstructions(
insertIndex + 1,
"""
# Move context to free register
iget-object v$freeRegister, v$freeRegister, $conversionContextFieldReference
invoke-static {v$freeRegister, v$atomicReferenceRegister, v$charSequenceSourceRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$freeRegister
# Replace the original instruction
move-object v${charSequenceTargetRegister}, v${freeRegister}
"""
)
}
} ?: throw TextComponentContextFingerprint.exception
// endregion
// region Hook rolling numbers.
RollingNumberSetterFingerprint.result?.let {
val dislikesIndex = it.scanResult.patternScanResult!!.endIndex
it.mutableMethod.apply {
val insertIndex = 1
val charSequenceInstanceRegister =
getInstruction<OneRegisterInstruction>(0).registerA
val charSequenceFieldReference =
getInstruction<ReferenceInstruction>(dislikesIndex).reference.toString()
val registerCount = implementation!!.registerCount
// This register is being overwritten, so it is free to use.
val freeRegister = registerCount - 1
val conversionContextRegister = registerCount - parameters.size + 1
addInstructions( addInstructions(
insertIndex, insertIndex,
""" """
iget-object v$freeRegister, v$charSequenceInstanceRegister, $charSequenceFieldReference # Copy conversion context
invoke-static {v$conversionContextRegister, v$freeRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onRollingNumberLoaded(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String; move-object/from16 v$tempRegister, p0
move-result-object v$freeRegister iget-object v$tempRegister, v$tempRegister, $conversionContextField
iput-object v$freeRegister, v$charSequenceInstanceRegister, $charSequenceFieldReference invoke-static {v$tempRegister, v$charSequenceRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
""" move-result-object v$charSequenceRegister
"""
) )
} }
} ?: throw RollingNumberSetterFingerprint.exception } ?: throw TextComponentConstructorFingerprint.exception
// Rolling Number text views use the measured width of the raw string for layout.
// Modify the measure text calculation to include the left drawable separator if needed.
RollingNumberMeasureAnimatedTextFingerprint.also {
if (!it.resolve(context, RollingNumberMeasureTextParentFingerprint.result!!.classDef))
throw it.exception
}.result?.also {
it.mutableMethod.apply {
val returnInstructionIndex = it.scanResult.patternScanResult!!.endIndex
val measuredTextWidthRegister =
getInstruction<OneRegisterInstruction>(returnInstructionIndex).registerA
replaceInstruction( // Replace instruction to preserve control flow label.
returnInstructionIndex,
"invoke-static {p1, v$measuredTextWidthRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F"
)
addInstructions(
returnInstructionIndex + 1,
"""
move-result v$measuredTextWidthRegister
return v$measuredTextWidthRegister
"""
)
}
} ?: throw RollingNumberMeasureAnimatedTextFingerprint.exception
// Additional text measurement method. Used if YouTube decides not to animate the likes count
// and sometimes used for initial video load.
RollingNumberMeasureStaticLabelFingerprint.also {
if (!it.resolve(context, RollingNumberMeasureTextParentFingerprint.result!!.classDef))
throw it.exception
}.result?.also {
it.mutableMethod.apply {
val measureTextIndex = it.scanResult.patternScanResult!!.startIndex + 1
val freeRegister = getInstruction<TwoRegisterInstruction>(0).registerA
addInstructions(
measureTextIndex + 1,
"""
move-result v$freeRegister
invoke-static {p1, v$freeRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F
"""
)
}
} ?: throw RollingNumberMeasureStaticLabelFingerprint.exception
// The rolling number Span is missing styling since it's initially set as a String.
// Modify the UI text view and use the styled like/dislike Span.
RollingNumberTextViewFingerprint.result?.let {
// Initial TextView is set in this method.
val initiallyCreatedTextViewMethod = it.mutableMethod
// Videos less than 24 hours after uploaded, like counts will be updated in real time.
// Whenever like counts are updated, TextView is set in this method.
val realTimeUpdateTextViewMethod =
RollingNumberTextViewAnimationUpdateFingerprint.result?.mutableMethod
?: throw RollingNumberTextViewAnimationUpdateFingerprint.exception
arrayOf(
initiallyCreatedTextViewMethod,
realTimeUpdateTextViewMethod
).forEach { insertMethod ->
insertMethod.apply {
val setTextIndex = indexOfFirstInstruction {
getReference<MethodReference>()?.name == "setText"
}
val textViewRegister =
getInstruction<FiveRegisterInstruction>(setTextIndex).registerC
val textSpanRegister =
getInstruction<FiveRegisterInstruction>(setTextIndex).registerD
addInstructions(
setTextIndex,
"""
invoke-static {v$textViewRegister, v$textSpanRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->updateRollingNumber(Landroid/widget/TextView;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$textSpanRegister
"""
)
}
}
} ?: throw RollingNumberTextViewFingerprint.exception
// endregion // endregion
@@ -335,6 +235,120 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
} ?: throw DislikesOldLayoutTextViewFingerprint.exception } ?: throw DislikesOldLayoutTextViewFingerprint.exception
// endregion // endregion
// region Hook rolling numbers.
// Do this last to allow patching old unsupported versions (if the user really wants),
// On older unsupported version this will fail to resolve and throw an exception,
// but everything will still work correctly anyways.
RollingNumberSetterFingerprint.result?.let {
val dislikesIndex = it.scanResult.patternScanResult!!.endIndex
it.mutableMethod.apply {
val insertIndex = 1
val charSequenceInstanceRegister =
getInstruction<OneRegisterInstruction>(0).registerA
val charSequenceFieldReference =
getInstruction<ReferenceInstruction>(dislikesIndex).reference
val registerCount = implementation!!.registerCount
// This register is being overwritten, so it is free to use.
val freeRegister = registerCount - 1
val conversionContextRegister = registerCount - parameters.size + 1
addInstructions(
insertIndex,
"""
iget-object v$freeRegister, v$charSequenceInstanceRegister, $charSequenceFieldReference
invoke-static {v$conversionContextRegister, v$freeRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onRollingNumberLoaded(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;
move-result-object v$freeRegister
iput-object v$freeRegister, v$charSequenceInstanceRegister, $charSequenceFieldReference
"""
)
}
} ?: throw RollingNumberSetterFingerprint.exception
// Rolling Number text views use the measured width of the raw string for layout.
// Modify the measure text calculation to include the left drawable separator if needed.
RollingNumberMeasureAnimatedTextFingerprint.result?.also {
val scanResult = it.scanResult.patternScanResult!!
// Additional check to verify the opcodes are at the start of the method
if (scanResult.startIndex != 0) throw PatchException("Unexpected opcode location")
val endIndex = scanResult.endIndex
it.mutableMethod.apply {
val measuredTextWidthRegister = getInstruction<OneRegisterInstruction>(endIndex).registerA
addInstructions(
endIndex + 1,
"""
invoke-static {p1, v$measuredTextWidthRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F
move-result v$measuredTextWidthRegister
"""
)
}
} ?: throw RollingNumberMeasureAnimatedTextFingerprint.exception
// Additional text measurement method. Used if YouTube decides not to animate the likes count
// and sometimes used for initial video load.
RollingNumberMeasureStaticLabelFingerprint.resolve(context, RollingNumberMeasureStaticLabelParentFingerprint.resultOrThrow().classDef)
RollingNumberMeasureStaticLabelFingerprint.result?.also {
val measureTextIndex = it.scanResult.patternScanResult!!.startIndex + 1
it.mutableMethod.apply {
val freeRegister = getInstruction<TwoRegisterInstruction>(0).registerA
addInstructions(
measureTextIndex + 1,
"""
move-result v$freeRegister
invoke-static {p1, v$freeRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F
"""
)
}
} ?: throw RollingNumberMeasureStaticLabelFingerprint.exception
// The rolling number Span is missing styling since it's initially set as a String.
// Modify the UI text view and use the styled like/dislike Span.
RollingNumberTextViewFingerprint.result?.let {
// Initial TextView is set in this method.
val initiallyCreatedTextViewMethod = it.mutableMethod
// Videos less than 24 hours after uploaded, like counts will be updated in real time.
// Whenever like counts are updated, TextView is set in this method.
val realTimeUpdateTextViewMethod =
RollingNumberTextViewAnimationUpdateFingerprint.result?.mutableMethod
?: throw RollingNumberTextViewAnimationUpdateFingerprint.exception
arrayOf(
initiallyCreatedTextViewMethod,
realTimeUpdateTextViewMethod
).forEach { insertMethod ->
insertMethod.apply {
val setTextIndex = indexOfFirstInstruction {
getReference<MethodReference>()?.name == "setText"
}
val textViewRegister =
getInstruction<FiveRegisterInstruction>(setTextIndex).registerC
val textSpanRegister =
getInstruction<FiveRegisterInstruction>(setTextIndex).registerD
addInstructions(
setTextIndex,
"""
invoke-static {v$textViewRegister, v$textSpanRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->updateRollingNumber(Landroid/widget/TextView;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$textSpanRegister
"""
)
}
}
} ?: throw RollingNumberTextViewFingerprint.exception
// endregion
} }
private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind) private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind)

View File

@@ -0,0 +1,18 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object ConversionContextFingerprint : MethodFingerprint(
returnType = "Ljava/lang/String;",
parameters = listOf(),
strings = listOf(
", widthConstraint=",
", heightConstraint=",
", templateLoggerFactory=",
", rootDisposableContainer=",
// 18.37.36 and after this String is: ConversionContext{containerInternal=
// and before it is: ConversionContext{container=
// Use a partial string to match both.
"ConversionContext{container"
)
)

View File

@@ -5,19 +5,24 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
/**
* Resolves to class found in [RollingNumberMeasureTextParentFingerprint].
*/
internal object RollingNumberMeasureAnimatedTextFingerprint : MethodFingerprint( internal object RollingNumberMeasureAnimatedTextFingerprint : MethodFingerprint(
returnType = "F", returnType = "Lj\$/util/Optional;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("Ljava/lang/String;"), parameters = listOf(
"L",
"Ljava/lang/String;",
"L"
),
opcodes = listOf( opcodes = listOf(
Opcode.INVOKE_VIRTUAL, Opcode.IGET, // First instruction of method
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.CONST_HIGH16,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT,
Opcode.ADD_FLOAT_2ADDR, Opcode.CONST_4,
Opcode.ADD_INT_LIT8, Opcode.AGET,
Opcode.GOTO, Opcode.CONST_4,
Opcode.RETURN Opcode.CONST_4, // Measured text width
) )
) )

View File

@@ -6,7 +6,7 @@ import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
/** /**
* Resolves to class found in [RollingNumberMeasureTextParentFingerprint]. * Resolves to class found in [RollingNumberMeasureStaticLabelParentFingerprint].
*/ */
internal object RollingNumberMeasureStaticLabelFingerprint : MethodFingerprint( internal object RollingNumberMeasureStaticLabelFingerprint : MethodFingerprint(
returnType = "F", returnType = "F",

View File

@@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal object RollingNumberMeasureTextParentFingerprint : MethodFingerprint( internal object RollingNumberMeasureStaticLabelParentFingerprint : MethodFingerprint(
returnType = "Ljava/lang/String;", returnType = "Ljava/lang/String;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(), parameters = listOf(),

View File

@@ -1,33 +0,0 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* Resolves against the same method that [TextComponentContextFingerprint] resolves to.
*/
internal object TextComponentAtomicReferenceFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
parameters = listOf("L"),
opcodes = listOf(
Opcode.MOVE_OBJECT, // Register B is free register
Opcode.MOVE_OBJECT_FROM16,
Opcode.MOVE_OBJECT_FROM16,
Opcode.MOVE_OBJECT_FROM16,
Opcode.MOVE_OBJECT_FROM16,
null,
Opcode.INVOKE_VIRTUAL, // Register C is atomic reference
Opcode.MOVE_RESULT_OBJECT, // Register A is char sequence
Opcode.CHECK_CAST,
Opcode.MOVE_OBJECT, // Replace this instruction with patch code
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.GOTO
)
)

View File

@@ -1,6 +1,5 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags

View File

@@ -1,27 +0,0 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* Resolves against the same class that [TextComponentConstructorFingerprint] resolves to.
*/
internal object TextComponentContextFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
parameters = listOf("L"),
opcodes = listOf(
Opcode.MOVE_OBJECT_FROM16,
Opcode.MOVE_OBJECT_FROM16,
Opcode.INVOKE_STATIC_RANGE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT, // conversion context field name
)
)

View File

@@ -0,0 +1,16 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object TextComponentDataFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L", "L"),
strings = listOf("text"),
customFingerprint = { _, classDef ->
val fields = classDef.fields
fields.find { it.type == "Ljava/util/BitSet;" } != null &&
fields.find { it.type == "[Ljava/lang/String;" } != null
}
)

View File

@@ -0,0 +1,15 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
/**
* Resolves against the same class that [TextComponentConstructorFingerprint] resolves to.
*/
internal object TextComponentLookupFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
parameters = listOf("L"),
strings = listOf("")
)

View File

@@ -26,8 +26,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.37.36", "18.37.36",
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -23,8 +23,11 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -38,13 +38,10 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube", [ "com.google.android.youtube", [
"18.32.39", "18.48.39",
"18.37.36", "18.49.37",
"18.38.44", "19.01.34",
"18.43.45", "19.02.34"
"18.44.41",
"18.45.41",
"18.45.43"
] ]
) )
], ],

View File

@@ -28,8 +28,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]
@@ -65,7 +68,7 @@ object SpoofAppVersionPatch : BytecodePatch(
StringResource("revanced_spoof_app_version_target_entry_2", "18.20.39 - Restore wide video speed & quality menu"), StringResource("revanced_spoof_app_version_target_entry_2", "18.20.39 - Restore wide video speed & quality menu"),
StringResource("revanced_spoof_app_version_target_entry_3", "17.08.35 - Restore old UI layout"), StringResource("revanced_spoof_app_version_target_entry_3", "17.08.35 - Restore old UI layout"),
StringResource("revanced_spoof_app_version_target_entry_4", "16.08.35 - Restore explore tab"), StringResource("revanced_spoof_app_version_target_entry_4", "16.08.35 - Restore explore tab"),
StringResource("revanced_spoof_app_version_target_entry_5", "16.01.35 - Restore old Shorts player"), StringResource("revanced_spoof_app_version_target_entry_5", "16.01.35 - Restore fewer video player action buttons"),
) )
), ),
ArrayResource( ArrayResource(

View File

@@ -24,8 +24,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -32,8 +32,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
) )
) )
] ]

View File

@@ -35,8 +35,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -40,8 +40,11 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -10,7 +10,7 @@ import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.patches.youtube.shared.fingerprints.WatchWhileActivityFingerprint import app.revanced.patches.youtube.shared.fingerprints.MainActivityFingerprint
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@Patch( @Patch(
@@ -21,15 +21,15 @@ import com.android.tools.smali.dexlib2.Opcode
) )
@Suppress("unused") @Suppress("unused")
object AnnouncementsPatch : BytecodePatch( object AnnouncementsPatch : BytecodePatch(
setOf(WatchWhileActivityFingerprint) setOf(MainActivityFingerprint)
) { ) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR = private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/announcements/AnnouncementsPatch;" "Lapp/revanced/integrations/youtube/patches/announcements/AnnouncementsPatch;"
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
val onCreateMethod = WatchWhileActivityFingerprint.result?.let { val onCreateMethod = MainActivityFingerprint.result?.let {
it.mutableClass.methods.find { method -> method.name == "onCreate" } it.mutableClass.methods.find { method -> method.name == "onCreate" }
} ?: throw WatchWhileActivityFingerprint.exception } ?: throw MainActivityFingerprint.exception
val superCallIndex = onCreateMethod.getInstructions().indexOfFirst { it.opcode == Opcode.INVOKE_SUPER_RANGE } val superCallIndex = onCreateMethod.getInstructions().indexOfFirst { it.opcode == Opcode.INVOKE_SUPER_RANGE }
@@ -43,7 +43,7 @@ object AnnouncementsPatch : BytecodePatch(
"revanced_announcements", "revanced_announcements",
StringResource( StringResource(
"revanced_announcements_title", "revanced_announcements_title",
"Show announcements from ReVanced" "Show ReVanced announcements"
), ),
StringResource( StringResource(
"revanced_announcements_summary_on", "revanced_announcements_summary_on",

View File

@@ -28,8 +28,11 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -23,12 +23,16 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]
) )
@Suppress("unused")
object SpoofDeviceDimensionsPatch : BytecodePatch( object SpoofDeviceDimensionsPatch : BytecodePatch(
setOf(DeviceDimensionsModelToStringFingerprint) setOf(DeviceDimensionsModelToStringFingerprint)
) { ) {

View File

@@ -1,6 +1,5 @@
package app.revanced.patches.youtube.misc.fix.backtoexitgesture package app.revanced.patches.youtube.misc.fix.backtoexitgesture
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
@@ -10,6 +9,7 @@ import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fingerprints.OnBa
import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fingerprints.RecyclerViewScrollingFingerprint import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fingerprints.RecyclerViewScrollingFingerprint
import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fingerprints.RecyclerViewTopScrollingFingerprint import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fingerprints.RecyclerViewTopScrollingFingerprint
import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fingerprints.RecyclerViewTopScrollingParentFingerprint import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fingerprints.RecyclerViewTopScrollingParentFingerprint
import app.revanced.util.exception
@Patch(description = "Fixes the swipe back to exit gesture.") @Patch(description = "Fixes the swipe back to exit gesture.")
@Suppress("unused") @Suppress("unused")
@@ -37,7 +37,7 @@ internal object FixBackToExitGesturePatch : BytecodePatch(
methodName = "onScrollingViews" methodName = "onScrollingViews"
), ),
OnBackPressedFingerprint to IntegrationsMethod( OnBackPressedFingerprint to IntegrationsMethod(
"p0", "onBackPressed", "Lcom/google/android/apps/youtube/app/watchwhile/WatchWhileActivity;" "p0", "onBackPressed", "Landroid/app/Activity;"
) )
).forEach { (fingerprint, target) -> fingerprint.injectCall(target) } ).forEach { (fingerprint, target) -> fingerprint.injectCall(target) }
} }

View File

@@ -12,7 +12,9 @@ internal object OnBackPressedFingerprint : MethodFingerprint(
Opcode.RETURN_VOID Opcode.RETURN_VOID
), ),
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.definingClass.endsWith("WatchWhileActivity;") (methodDef.definingClass.endsWith("MainActivity;") ||
// Old versions of YouTube called this class "WatchWhileActivity" instead.
methodDef.definingClass.endsWith("WatchWhileActivity;"))
&& methodDef.name == "onBackPressed" && methodDef.name == "onBackPressed"
} }
) )

View File

@@ -10,22 +10,17 @@ import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.UserAgentHeaderBuilderFingerprint import app.revanced.patches.youtube.misc.fix.playback.fingerprints.UserAgentHeaderBuilderFingerprint
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@Patch( @Patch(
name = "Client spoof", name = "Client spoof",
description = "Adds options to spoof the client to allow video playback.", description = "Adds options to spoof the client to allow video playback.",
dependencies = [SpoofSignaturePatch::class], dependencies = [SpoofSignaturePatch::class],
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube", "com.google.android.youtube", [
[ "18.48.39",
"18.32.39", "18.49.37",
"18.37.36", "19.01.34",
"18.38.44", "19.02.34"
"18.43.45",
"18.44.41",
"18.45.41",
"18.45.43"
] ]
) )
] ]

View File

@@ -33,13 +33,10 @@ object GmsCoreSupportPatch : AbstractGmsCoreSupportPatch(
compatiblePackages = setOf( compatiblePackages = setOf(
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube", setOf( "com.google.android.youtube", setOf(
"18.32.39", "18.48.39",
"18.37.36", "18.49.37",
"18.38.44", "19.01.34",
"18.43.45", "19.02.34"
"18.44.41",
"18.45.41",
"18.45.43"
) )
) )
), ),

View File

@@ -25,12 +25,16 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
[ [
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]
) )
@Suppress("unused")
object BypassURLRedirectsPatch : BytecodePatch( object BypassURLRedirectsPatch : BytecodePatch(
setOf(ABUriParserFingerprint, HTTPUriParserFingerprint) setOf(ABUriParserFingerprint, HTTPUriParserFingerprint)
) { ) {

View File

@@ -28,8 +28,11 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -34,13 +34,10 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube", "com.google.android.youtube",
[ [
"18.32.39", "18.48.39",
"18.37.36", "18.49.37",
"18.38.44", "19.01.34",
"18.43.45", "19.02.34"
"18.44.41",
"18.45.41",
"18.45.43"
] ]
) )
] ]

View File

@@ -30,8 +30,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
[ [
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -4,10 +4,12 @@ import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal object WatchWhileActivityFingerprint : MethodFingerprint( internal object MainActivityFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf(), parameters = listOf(),
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.definingClass.endsWith("WatchWhileActivity;") methodDef.definingClass.endsWith("MainActivity;")
// Old versions of YouTube called this class "WatchWhileActivity" instead.
|| methodDef.definingClass.endsWith("WatchWhileActivity;")
} }
) )

View File

@@ -26,8 +26,11 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]

View File

@@ -1,6 +1,5 @@
package app.revanced.patches.youtube.video.information package app.revanced.patches.youtube.video.information
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
@@ -14,13 +13,14 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.video.information.fingerprints.* import app.revanced.patches.youtube.video.information.fingerprints.*
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
import app.revanced.patches.youtube.video.videoid.VideoIdPatch import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.exception
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.BuilderInstruction import com.android.tools.smali.dexlib2.builder.BuilderInstruction
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import com.android.tools.smali.dexlib2.util.MethodUtil import com.android.tools.smali.dexlib2.util.MethodUtil
@@ -135,23 +135,24 @@ object VideoInformationPatch : BytecodePatch(
*/ */
videoTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime") videoTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime")
/* /*
* Hook the user playback speed selection * Hook the user playback speed selection
*/ */
OnPlaybackSpeedItemClickFingerprint.result?.apply { OnPlaybackSpeedItemClickFingerprint.result?.mutableMethod?.apply {
speedSelectionInsertMethod = mutableMethod speedSelectionInsertMethod = this
speedSelectionInsertIndex = scanResult.patternScanResult!!.startIndex - 3 val speedSelectionMethodInstructions = this.implementation!!.instructions
val speedSelectionValueInstructionIndex = speedSelectionMethodInstructions.indexOfFirst {
it.opcode == Opcode.IGET
}
speedSelectionValueRegister = speedSelectionValueRegister =
mutableMethod.getInstruction<FiveRegisterInstruction>(speedSelectionInsertIndex).registerD getInstruction<TwoRegisterInstruction>(speedSelectionValueInstructionIndex).registerA
setPlaybackSpeedClassFieldReference =
val speedSelectionMethodInstructions = mutableMethod.implementation!!.instructions getInstruction<ReferenceInstruction>(speedSelectionValueInstructionIndex + 1).reference.toString()
setPlaybackSpeedMethodReference =
getInstruction<ReferenceInstruction>(speedSelectionValueInstructionIndex + 2).reference.toString()
setPlaybackSpeedContainerClassFieldReference = setPlaybackSpeedContainerClassFieldReference =
getReference(speedSelectionMethodInstructions, -1, Opcode.IF_EQZ) getReference(speedSelectionMethodInstructions, -1, Opcode.IF_EQZ)
setPlaybackSpeedClassFieldReference = speedSelectionInsertIndex = speedSelectionValueInstructionIndex + 1
getReference(speedSelectionMethodInstructions, 1, Opcode.IGET)
setPlaybackSpeedMethodReference =
getReference(speedSelectionMethodInstructions, 2, Opcode.IGET)
} ?: throw OnPlaybackSpeedItemClickFingerprint.exception } ?: throw OnPlaybackSpeedItemClickFingerprint.exception
userSelectedPlaybackSpeedHook(INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed") userSelectedPlaybackSpeedHook(INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")

View File

@@ -2,18 +2,19 @@ package app.revanced.patches.youtube.video.information.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
internal object OnPlaybackSpeedItemClickFingerprint : MethodFingerprint( internal object OnPlaybackSpeedItemClickFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "V", returnType = "V",
parameters = listOf("L", "L", "I", "J"), parameters = listOf("L", "L", "I", "J"),
customFingerprint = { methodDef, _ -> methodDef.name == "onItemClick" }, customFingerprint = { methodDef, _ ->
opcodes = listOf( methodDef.name == "onItemClick" && methodDef.implementation?.instructions?.find {
Opcode.MOVE_RESULT_OBJECT, it.opcode == Opcode.IGET_OBJECT &&
Opcode.INVOKE_VIRTUAL, it.getReference<FieldReference>()!!.type == "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"
Opcode.INVOKE_VIRTUAL, } != null
Opcode.RETURN_VOID }
)
) )

View File

@@ -18,29 +18,44 @@ object PlayerResponseMethodHookPatch :
BytecodePatch(setOf(PlayerParameterBuilderFingerprint)), BytecodePatch(setOf(PlayerParameterBuilderFingerprint)),
Closeable, Closeable,
MutableSet<PlayerResponseMethodHookPatch.Hook> by mutableSetOf() { MutableSet<PlayerResponseMethodHookPatch.Hook> by mutableSetOf() {
private const val VIDEO_ID_PARAMETER = 1
private const val IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER = 11 // Parameter numbers of the patched method.
private const val PROTO_BUFFER_PARAMETER_PARAMETER = 3 private const val PARAMETER_VIDEO_ID = 1
private const val PARAMETER_PROTO_BUFFER = 3
private const val PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = 11
// Temporary 4-bit registers used to pass the parameters to integrations.
private const val REGISTER_VIDEO_ID = 0
private const val REGISTER_PROTO_BUFFER = 1
private const val REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING = 2
private lateinit var playerResponseMethod: MutableMethod private lateinit var playerResponseMethod: MutableMethod
private var numberOfInstructionsAdded = 0
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
playerResponseMethod = PlayerParameterBuilderFingerprint.result?.mutableMethod playerResponseMethod = PlayerParameterBuilderFingerprint.result?.mutableMethod
?: throw PlayerParameterBuilderFingerprint.exception ?: throw PlayerParameterBuilderFingerprint.exception
} }
override fun close() { override fun close() {
fun hookVideoId(hook: Hook) = playerResponseMethod.addInstruction( fun hookVideoId(hook: Hook) {
0, "invoke-static {p$VIDEO_ID_PARAMETER, p$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook" playerResponseMethod.addInstruction(
) 0, "invoke-static {v$REGISTER_VIDEO_ID, v$REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook"
)
numberOfInstructionsAdded++
}
fun hookProtoBufferParameter(hook: Hook) = playerResponseMethod.addInstructions( fun hookProtoBufferParameter(hook: Hook) {
0, playerResponseMethod.addInstructions(
0,
"""
invoke-static {v$REGISTER_PROTO_BUFFER, v$REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook
move-result-object v$REGISTER_PROTO_BUFFER
""" """
invoke-static {p$PROTO_BUFFER_PARAMETER_PARAMETER, p$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook )
move-result-object p$PROTO_BUFFER_PARAMETER_PARAMETER numberOfInstructionsAdded += 2
""" }
)
// Reverse the order in order to preserve insertion order of the hooks. // Reverse the order in order to preserve insertion order of the hooks.
val beforeVideoIdHooks = filterIsInstance<Hook.ProtoBufferParameterBeforeVideoId>().asReversed() val beforeVideoIdHooks = filterIsInstance<Hook.ProtoBufferParameterBeforeVideoId>().asReversed()
@@ -51,6 +66,23 @@ object PlayerResponseMethodHookPatch :
afterVideoIdHooks.forEach(::hookProtoBufferParameter) afterVideoIdHooks.forEach(::hookProtoBufferParameter)
videoIdHooks.forEach(::hookVideoId) videoIdHooks.forEach(::hookVideoId)
beforeVideoIdHooks.forEach(::hookProtoBufferParameter) beforeVideoIdHooks.forEach(::hookProtoBufferParameter)
// On some app targets the method has too many registers pushing the parameters past v15.
// Move the parameters to 4-bit registers so they can be passed to integrations.
playerResponseMethod.addInstructions(
0, """
move-object/from16 v$REGISTER_VIDEO_ID, p$PARAMETER_VIDEO_ID
move-object/from16 v$REGISTER_PROTO_BUFFER, p$PARAMETER_PROTO_BUFFER
move/from16 v$REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING
""",
)
numberOfInstructionsAdded += 3
// Move the modified register back.
playerResponseMethod.addInstruction(
numberOfInstructionsAdded,
"move-object/from16 p$PARAMETER_PROTO_BUFFER, v$REGISTER_PROTO_BUFFER"
)
} }
internal abstract class Hook(private val methodDescriptor: String) { internal abstract class Hook(private val methodDescriptor: String) {

View File

@@ -31,13 +31,10 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube", [ "com.google.android.youtube", [
"18.32.39", "18.48.39",
"18.37.36", "18.49.37",
"18.38.44", "19.01.34",
"18.43.45", "19.02.34"
"18.44.41",
"18.45.41",
"18.45.43"
] ]
) )
] ]

View File

@@ -14,13 +14,10 @@ import app.revanced.patches.youtube.video.speed.remember.RememberPlaybackSpeedPa
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
"com.google.android.youtube", [ "com.google.android.youtube", [
"18.32.39", "18.48.39",
"18.37.36", "18.49.37",
"18.38.44", "19.01.34",
"18.43.45", "19.02.34"
"18.44.41",
"18.45.41",
"18.45.43"
] ]
) )
] ]

View File

@@ -29,7 +29,13 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableField
@Patch( @Patch(
description = "Adds custom playback speed options.", description = "Adds custom playback speed options.",
dependencies = [IntegrationsPatch::class, LithoFilterPatch::class, SettingsPatch::class, RecyclerViewTreeHookPatch::class] dependencies = [
IntegrationsPatch::class,
LithoFilterPatch::class,
SettingsPatch::class,
RecyclerViewTreeHookPatch::class,
CustomPlaybackSpeedResourcePatch::class
]
) )
object CustomPlaybackSpeedPatch : BytecodePatch( object CustomPlaybackSpeedPatch : BytecodePatch(
setOf( setOf(

View File

@@ -0,0 +1,15 @@
package app.revanced.patches.youtube.video.speed.custom
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch
internal object CustomPlaybackSpeedResourcePatch : ResourcePatch() {
var speedUnavailableId: Long = -1
override fun execute(context: ResourceContext) {
speedUnavailableId = ResourceMappingPatch.resourceMappings.single {
it.type == "string" && it.name == "varispeed_unavailable_message"
}.id
}
}

View File

@@ -1,7 +1,10 @@
package app.revanced.patches.youtube.video.speed.custom.fingerprints package app.revanced.patches.youtube.video.speed.custom.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patches.youtube.video.speed.custom.CustomPlaybackSpeedResourcePatch
import app.revanced.util.patch.LiteralValueFingerprint
internal object ShowOldPlaybackSpeedMenuFingerprint : MethodFingerprint( internal object ShowOldPlaybackSpeedMenuFingerprint : LiteralValueFingerprint(
strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT") literalSupplier = {
CustomPlaybackSpeedResourcePatch.speedUnavailableId
}
) )

View File

@@ -1,6 +1,5 @@
package app.revanced.patches.youtube.video.videoid package app.revanced.patches.youtube.video.videoid
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
@@ -13,6 +12,7 @@ import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprint import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprint
import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprintBackgroundPlay import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprintBackgroundPlay
import app.revanced.util.exception
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch( @Patch(
@@ -49,7 +49,7 @@ object VideoIdPatch : BytecodePatch(
consumer(it, insertIndex, videoIdRegister) consumer(it, insertIndex, videoIdRegister)
} }
} ?: throw VideoIdFingerprint.exception } ?: throw exception
VideoIdFingerprint.setFields { method, index, register -> VideoIdFingerprint.setFields { method, index, register ->
videoIdMethod = method videoIdMethod = method

View File

@@ -10,19 +10,13 @@ internal object VideoIdFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L"), parameters = listOf("L"),
opcodes = listOf( opcodes = listOf(
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_EQZ,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_EQZ, Opcode.IF_EQZ,
Opcode.IGET_OBJECT, Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL, Opcode.IGET_OBJECT,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE, Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE, Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT Opcode.MOVE_RESULT_OBJECT,
) )
) )

View File

@@ -10,18 +10,10 @@ internal object VideoIdFingerprintBackgroundPlay : MethodFingerprint(
accessFlags = AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC, accessFlags = AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC,
parameters = listOf("L"), parameters = listOf("L"),
opcodes = listOf( opcodes = listOf(
Opcode.MONITOR_EXIT,
Opcode.RETURN_VOID,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.NEW_ARRAY,
Opcode.SGET_OBJECT,
Opcode.APUT_OBJECT,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT,
Opcode.IF_EQZ, Opcode.IF_EQZ,
Opcode.INVOKE_VIRTUAL, Opcode.IGET_OBJECT,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_EQZ, Opcode.IF_EQZ,
Opcode.INVOKE_INTERFACE, Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,

View File

@@ -30,8 +30,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.38.44", "18.38.44",
"18.43.45", "18.43.45",
"18.44.41", "18.44.41",
"18.45.41", "18.45.43",
"18.45.43" "18.48.39",
"18.49.37",
"19.01.34",
"19.02.34"
] ]
) )
] ]