fix(core): opera viewer params override

supports v13.22.0.61 and higher

Signed-off-by: rhunk <101876869+rhunk@users.noreply.github.com>
This commit is contained in:
rhunk 2025-01-10 15:25:49 +01:00
parent c7cb25c190
commit 2c435a3760
3 changed files with 19 additions and 25 deletions

View File

@ -2,8 +2,10 @@ package me.rhunk.snapenhance.core.features.impl
import me.rhunk.snapenhance.core.features.Feature
import me.rhunk.snapenhance.core.util.hook.HookStage
import me.rhunk.snapenhance.core.util.hook.hook
import me.rhunk.snapenhance.core.util.hook.hookConstructor
import me.rhunk.snapenhance.core.wrapper.impl.media.opera.ParamMap
import me.rhunk.snapenhance.mapper.impl.OperaViewerParamsMapper
import java.util.concurrent.ConcurrentHashMap
class OperaViewerParamsOverride : Feature("OperaViewerParamsOverride") {
var currentPlaybackRate = 1.0F
@ -37,7 +39,7 @@ class OperaViewerParamsOverride : Feature("OperaViewerParamsOverride") {
overrideParam("auto_advance_max_loop_number", { true }, { _, _ -> Int.MAX_VALUE })
overrideParam("media_playback_mode", { true }, { _, value ->
val playbackMode = value ?: return@overrideParam null
playbackMode::class.java.enumConstants.firstOrNull {
playbackMode::class.java.enumConstants?.firstOrNull {
it.toString() == "LOOPING"
} ?: return@overrideParam value
})
@ -69,12 +71,16 @@ class OperaViewerParamsOverride : Feature("OperaViewerParamsOverride") {
return value
}
classReference.get()?.hook(getMethod.get()!!, HookStage.AFTER) { param ->
param.setResult(overrideParamResult(param.arg(0), param.getResult()))
classReference.get()?.hookConstructor(HookStage.AFTER) { param ->
ParamMap(param.thisObject()).paramMapField.set(param.thisObject(), object: ConcurrentHashMap<Any, Any>() {
override fun put(key: Any, value: Any): Any? {
return super.put(key, overrideParamResult(key, value) ?: return value)
}
classReference.get()?.hook(getOrDefaultMethod.get()!!, HookStage.AFTER) { param ->
param.setResult(overrideParamResult(param.arg(0), param.getResult()))
override fun get(key: Any): Any? {
return overrideParamResult(key, super.get(key))
}
})
}
}
}

View File

@ -8,7 +8,7 @@ import java.util.concurrent.ConcurrentHashMap
@Suppress("UNCHECKED_CAST")
class ParamMap(obj: Any?) : AbstractWrapper(obj) {
private val paramMapField: Field by lazy {
val paramMapField: Field by lazy {
instanceNonNull()::class.java.findFields(once = true) {
it.type == ConcurrentHashMap::class.java || runCatching { it.get(instance) }.getOrNull() is ConcurrentHashMap<*, *>
}.firstOrNull() ?: throw RuntimeException("Could not find paramMap field")

View File

@ -9,8 +9,6 @@ import me.rhunk.snapenhance.mapper.ext.getClassName
class OperaViewerParamsMapper : AbstractClassMapper("OperaViewerParams") {
val classReference = classReference("class")
val getMethod = string("getMethod")
val getOrDefaultMethod = string("getOrDefaultMethod")
private fun Method.hasHashMapReference(methodName: String) = implementation?.instructions?.any {
val instruction = it as? Instruction35c ?: return@any false
@ -21,25 +19,15 @@ class OperaViewerParamsMapper : AbstractClassMapper("OperaViewerParams") {
init {
mapper {
for (classDef in classes) {
classDef.fields.firstOrNull { it.type == "Ljava/util/concurrent/ConcurrentHashMap;" } ?: continue
if (classDef.methods.firstOrNull { it.name == "toString" }?.implementation?.findConstString("Params") != true) continue
val getOrDefaultDexMethod = classDef.methods.firstOrNull { method ->
classDef.methods.firstOrNull { method ->
method.returnType == "Ljava/lang/Object;" &&
method.parameters.size == 2 &&
method.parameterTypes[1] == "Ljava/lang/Object;" &&
method.hasHashMapReference("get")
} ?: return@mapper
} ?: continue
val getDexMethod = classDef.methods.firstOrNull { method ->
method.returnType == "Ljava/lang/Object;" &&
method.parameters.size == 1 &&
method.parameterTypes[0] == getOrDefaultDexMethod.parameterTypes[0] &&
method.hasHashMapReference("get")
} ?: return@mapper
getMethod.set(getDexMethod.name)
getOrDefaultMethod.set(getOrDefaultDexMethod.name)
classReference.set(classDef.getClassName())
return@mapper
}