feat: media quality level override

This commit is contained in:
rhunk
2023-05-26 20:47:22 +02:00
parent de1a676084
commit e7ccaf312e
5 changed files with 94 additions and 14 deletions

View File

@@ -12,7 +12,8 @@
"action": { "action": {
"clean_cache": "Clean Cache", "clean_cache": "Clean Cache",
"clear_message_logger": "Clear Message Logger" "clear_message_logger": "Clear Message Logger",
"refresh_mappings": "Refresh Mappings"
}, },
"property": { "property": {
@@ -41,11 +42,14 @@
"auto_save": "Auto Save", "auto_save": "Auto Save",
"anti_auto_save": "Anti Auto Save Button", "anti_auto_save": "Anti Auto Save Button",
"snapchat_plus": "Snapchat Plus", "snapchat_plus": "Snapchat Plus",
"disable_snap_splitting": "Disable Snap Splitting",
"disable_video_length_restriction": "Disable Video Length Restriction",
"override_media_quality": "Override Media Quality",
"media_quality_level": "Media Quality Level",
"remove_voice_record_button": "Remove Voice Record Button", "remove_voice_record_button": "Remove Voice Record Button",
"remove_stickers_button": "Remove Stickers Button", "remove_stickers_button": "Remove Stickers Button",
"remove_cognac_button": "Remove Cognac Button", "remove_cognac_button": "Remove Cognac Button",
"remove_call_buttons": "Remove Call Buttons", "remove_call_buttons": "Remove Call Buttons",
"disable_snap_splitting": "Disable Snap Splitting",
"block_ads": "Block Ads", "block_ads": "Block Ads",
"streak_expiration_info": "Show Streak Expiration Info", "streak_expiration_info": "Show Streak Expiration Info",
"new_map_ui": "New Map UI", "new_map_ui": "New Map UI",

View File

@@ -3,6 +3,7 @@ package me.rhunk.snapenhance.config
import android.os.Environment import android.os.Environment
import me.rhunk.snapenhance.config.impl.ConfigIntegerValue import me.rhunk.snapenhance.config.impl.ConfigIntegerValue
import me.rhunk.snapenhance.config.impl.ConfigStateListValue import me.rhunk.snapenhance.config.impl.ConfigStateListValue
import me.rhunk.snapenhance.config.impl.ConfigStateSelection
import me.rhunk.snapenhance.config.impl.ConfigStateValue import me.rhunk.snapenhance.config.impl.ConfigStateValue
import me.rhunk.snapenhance.config.impl.ConfigStringValue import me.rhunk.snapenhance.config.impl.ConfigStringValue
import java.io.File import java.io.File
@@ -143,6 +144,33 @@ enum class ConfigProperty(
ANTI_AUTO_SAVE("property.anti_auto_save", "description.anti_auto_save", ConfigCategory.EXTRAS, ConfigStateValue(false)), ANTI_AUTO_SAVE("property.anti_auto_save", "description.anti_auto_save", ConfigCategory.EXTRAS, ConfigStateValue(false)),
SNAPCHAT_PLUS("property.snapchat_plus", "description.snapchat_plus", ConfigCategory.EXTRAS, ConfigStateValue(false)), SNAPCHAT_PLUS("property.snapchat_plus", "description.snapchat_plus", ConfigCategory.EXTRAS, ConfigStateValue(false)),
DISABLE_SNAP_SPLITTING(
"property.disable_snap_splitting",
"description.disable_snap_splitting",
ConfigCategory.TWEAKS,
ConfigStateValue(false)
),
DISABLE_VIDEO_LENGTH_RESTRICTION(
"property.disable_video_length_restriction",
"description.disable_video_length_restriction",
ConfigCategory.TWEAKS,
ConfigStateValue(false)
),
OVERRIDE_MEDIA_QUALITY(
"property.override_media_quality",
"description.override_media_quality",
ConfigCategory.TWEAKS,
ConfigStateValue(false)
),
MEDIA_QUALITY_LEVEL(
"property.media_quality_level",
"description.media_quality_level",
ConfigCategory.TWEAKS,
ConfigStateSelection(
listOf("LEVEL_NONE", "LEVEL_1", "LEVEL_2", "LEVEL_3", "LEVEL_4", "LEVEL_5", "LEVEL_6", "LEVEL_7", "LEVEL_MAX"),
"LEVEL_NONE"
)
),
REMOVE_VOICE_RECORD_BUTTON( REMOVE_VOICE_RECORD_BUTTON(
"property.remove_voice_record_button", "property.remove_voice_record_button",
"description.remove_voice_record_button", "description.remove_voice_record_button",
@@ -167,18 +195,6 @@ enum class ConfigProperty(
ConfigCategory.TWEAKS, ConfigCategory.TWEAKS,
ConfigStateValue(false) ConfigStateValue(false)
), ),
DISABLE_SNAP_SPLITTING(
"property.disable_snap_splitting",
"description.disable_snap_splitting",
ConfigCategory.TWEAKS,
ConfigStateValue(false)
),
DISABLE_VIDEO_LENGTH_RESTRICTION(
"property.disable_video_length_restriction",
"description.disable_video_length_restriction",
ConfigCategory.TWEAKS,
ConfigStateValue(false)
),
BLOCK_ADS("property.block_ads", "description.block_ads", ConfigCategory.TWEAKS, ConfigStateValue(false)), BLOCK_ADS("property.block_ads", "description.block_ads", ConfigCategory.TWEAKS, ConfigStateValue(false)),
STREAK_EXPIRATION_INFO( STREAK_EXPIRATION_INFO(
"property.streak_expiration_info", "property.streak_expiration_info",

View File

@@ -0,0 +1,32 @@
package me.rhunk.snapenhance.features.impl.extras
import me.rhunk.snapenhance.Logger
import me.rhunk.snapenhance.config.ConfigProperty
import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams
import me.rhunk.snapenhance.hook.HookStage
import me.rhunk.snapenhance.hook.Hooker
class MediaQualityLevelOverride : Feature("MediaQualityLevelOverride", loadParams = FeatureLoadParams.INIT_SYNC) {
override fun init() {
val enumQualityLevel = context.mappings.getMappedClass("enums", "QualityLevel")
Hooker.hookConstructor(context.androidContext.classLoader.loadClass("hfj"), HookStage.AFTER) {
Logger.log(it.thisObject())
}
Hooker.hook(context.mappings.getMappedClass("MediaQualityLevelProvider"),
context.mappings.getMappedValue("MediaQualityLevelProviderMethod"),
HookStage.BEFORE,
{context.config.bool(ConfigProperty.OVERRIDE_MEDIA_QUALITY)}
) { param ->
val currentCompressionLevel = enumQualityLevel.enumConstants
.firstOrNull { it.toString() == context.config.state(ConfigProperty.MEDIA_QUALITY_LEVEL)} ?: run {
context.longToast("Invalid media quality level: ${context.config.state(ConfigProperty.MEDIA_QUALITY_LEVEL)}")
return@hook
}
Logger.debug("set media compression level to $currentCompressionLevel")
param.setResult(currentCompressionLevel)
}
}
}

View File

@@ -10,6 +10,7 @@ import me.rhunk.snapenhance.features.impl.downloader.AntiAutoDownload
import me.rhunk.snapenhance.features.impl.downloader.MediaDownloader import me.rhunk.snapenhance.features.impl.downloader.MediaDownloader
import me.rhunk.snapenhance.features.impl.extras.AntiAutoSave import me.rhunk.snapenhance.features.impl.extras.AntiAutoSave
import me.rhunk.snapenhance.features.impl.extras.AutoSave import me.rhunk.snapenhance.features.impl.extras.AutoSave
import me.rhunk.snapenhance.features.impl.extras.MediaQualityLevelOverride
import me.rhunk.snapenhance.features.impl.extras.DisableVideoLengthRestriction import me.rhunk.snapenhance.features.impl.extras.DisableVideoLengthRestriction
import me.rhunk.snapenhance.features.impl.extras.ExternalMediaAsSnap import me.rhunk.snapenhance.features.impl.extras.ExternalMediaAsSnap
import me.rhunk.snapenhance.features.impl.extras.Notifications import me.rhunk.snapenhance.features.impl.extras.Notifications
@@ -68,6 +69,7 @@ class FeatureManager(private val context: ModContext) : Manager {
register(AntiAutoSave::class) register(AntiAutoSave::class)
register(UnlimitedSnapViewTime::class) register(UnlimitedSnapViewTime::class)
register(DisableVideoLengthRestriction::class) register(DisableVideoLengthRestriction::class)
register(MediaQualityLevelOverride::class)
initializeFeatures() initializeFeatures()
} }
@@ -80,6 +82,7 @@ class FeatureManager(private val context: ModContext) : Manager {
action(feature) action(feature)
}.onFailure { }.onFailure {
Logger.xposedLog("Failed to init feature ${feature.nameKey}", it) Logger.xposedLog("Failed to init feature ${feature.nameKey}", it)
context.longToast("Failed to init feature ${feature.nameKey}")
} }
} }
if (!isAsync) { if (!isAsync) {

View File

@@ -1,8 +1,10 @@
package me.rhunk.snapenhance.mapping.impl package me.rhunk.snapenhance.mapping.impl
import me.rhunk.snapenhance.Logger
import me.rhunk.snapenhance.Logger.debug import me.rhunk.snapenhance.Logger.debug
import me.rhunk.snapenhance.mapping.Mapper import me.rhunk.snapenhance.mapping.Mapper
import java.lang.reflect.Method import java.lang.reflect.Method
import java.lang.reflect.Modifier
import java.util.Objects import java.util.Objects
@@ -13,11 +15,22 @@ class EnumMapper : Mapper() {
mappings: MutableMap<String, Any> mappings: MutableMap<String, Any>
) { ) {
val enumMappings = HashMap<String, String>() val enumMappings = HashMap<String, String>()
var enumQualityLevel: Class<*>? = null
//settings classes have an interface that extends Serializable and contains the getName method //settings classes have an interface that extends Serializable and contains the getName method
//this enum classes are used to store the settings values //this enum classes are used to store the settings values
//Setting enum class -> implements an interface -> getName method //Setting enum class -> implements an interface -> getName method
classes.forEach { clazz -> classes.forEach { clazz ->
if (!clazz.isEnum) return@forEach if (!clazz.isEnum) return@forEach
//quality level enum
if (enumQualityLevel == null) {
if (clazz.enumConstants.any { it.toString().startsWith("LEVEL_NONE") }) {
enumMappings["QualityLevel"] = clazz.name
enumQualityLevel = clazz
}
}
if (clazz.interfaces.isEmpty()) return@forEach if (clazz.interfaces.isEmpty()) return@forEach
val serializableInterfaceClass = clazz.interfaces[0] val serializableInterfaceClass = clazz.interfaces[0]
if (serializableInterfaceClass.methods if (serializableInterfaceClass.methods
@@ -35,6 +48,18 @@ class EnumMapper : Mapper() {
} }
} }
} }
//find the media quality level provider
for (clazz in classes) {
if (!Modifier.isAbstract(clazz.modifiers)) continue
if (clazz.fields.none { Modifier.isTransient(it.modifiers) }) continue
clazz.methods.firstOrNull { it.returnType == enumQualityLevel }?.let {
mappings["MediaQualityLevelProvider"] = clazz.name
mappings["MediaQualityLevelProviderMethod"] = it.name
Logger.debug("found MediaQualityLevelProvider: ${clazz.name}.${it.name}")
}
}
debug("found " + enumMappings.size + " enums") debug("found " + enumMappings.size + " enums")
mappings["enums"] = enumMappings mappings["enums"] = enumMappings
} }