feat: media upload quality override

This commit is contained in:
rhunk
2024-05-14 21:28:57 +02:00
parent fad13ee7a2
commit 62ff1d998f
6 changed files with 78 additions and 30 deletions

View File

@@ -686,6 +686,24 @@
"name": "Snapchat Plus",
"description": "Enables Snapchat Plus features\nSome Server-sided features may not work"
},
"media_upload_quality": {
"name": "Media Upload Quality",
"description": "Overrides the media upload quality",
"properties": {
"force_video_upload_source_quality": {
"name": "Force Video Upload Source Quality",
"description": "Forces Snapchat to use the source quality when uploading videos\nPlease note that this may not remove metadata from media"
},
"disable_image_compression": {
"name": "Disable Image Compression",
"description": "Disables image compression when uploading media"
},
"custom_image_upload_format": {
"name": "Custom Image Upload Format",
"description": "Sets a custom image upload format\nSelect a lossless format (like PNG) for the best quality"
}
}
},
"disable_confirmation_dialogs": {
"name": "Disable Confirmation Dialogs",
"description": "Automatically confirms selected actions"
@@ -738,10 +756,6 @@
"name": "Disable Google Play Services Dialogs",
"description": "Prevent Google Play Services availability dialogs from being shown"
},
"force_upload_source_quality": {
"name": "Force Upload Source Quality",
"description": "Forces Snapchat to upload media in the original quality\nPlease note that this may not remove metadata from media"
},
"default_volume_controls": {
"name": "Default Volume Controls",
"description": "Forces Snapchat to use system volume controls"

View File

@@ -1,6 +1,7 @@
package me.rhunk.snapenhance.common.config.impl
import me.rhunk.snapenhance.common.config.ConfigContainer
import me.rhunk.snapenhance.common.config.ConfigFlag
import me.rhunk.snapenhance.common.config.FeatureNotice
class Global : ConfigContainer() {
@@ -27,8 +28,16 @@ class Global : ConfigContainer() {
val spoofBatteryLevel = string("spoof_battery_level") { requireRestart(); inputCheck = { it.isEmpty() || it.toIntOrNull() in 0..100 } }
val spoofHeadphones = boolean("spoof_headphones") { requireRestart() }
}
inner class MediaUploadQualityConfig : ConfigContainer() {
val forceVideoUploadSourceQuality = boolean("force_video_upload_source_quality") { requireRestart() }
val disableImageCompression = boolean("disable_image_compression") { requireRestart() }
val customUploadImageFormat = unique("custom_image_upload_format", "jpeg", "png", "webp") { requireRestart(); addFlags(ConfigFlag.NO_TRANSLATE) }
}
val betterLocation = container("better_location", BetterLocation())
val snapchatPlus = boolean("snapchat_plus") { requireRestart() }
val mediaUploadQualityConfig = container("media_upload_quality", MediaUploadQualityConfig())
val disableConfirmationDialogs = multiple("disable_confirmation_dialogs", "erase_message", "remove_friend", "block_friend", "ignore_friend", "hide_friend", "hide_conversation", "clear_conversation") { requireRestart() }
val disableMetrics = boolean("disable_metrics") { requireRestart() }
val disableStorySections = multiple("disable_story_sections", "friends", "following", "discover") { requireRestart(); requireCleanCache() }
@@ -42,7 +51,6 @@ class Global : ConfigContainer() {
val defaultVideoPlaybackRate = float("default_video_playback_rate", 1.0F) { requireRestart(); inputCheck = { (it.toFloatOrNull() ?: 1.0F) in 0.1F..4.0F} }
val videoPlaybackRateSlider = boolean("video_playback_rate_slider") { requireRestart() }
val disableGooglePlayDialogs = boolean("disable_google_play_dialogs") { requireRestart() }
val forceUploadSourceQuality = boolean("force_upload_source_quality") { requireRestart() }
val defaultVolumeControls = boolean("default_volume_controls") { requireRestart() }
val hideActiveMusic = boolean("hide_active_music") { requireRestart() }
val disableSnapSplitting = boolean("disable_snap_splitting") { addNotices(FeatureNotice.INTERNAL_BEHAVIOR) }

View File

@@ -79,7 +79,7 @@ class FeatureManager(
SendOverride(),
UnlimitedSnapViewTime(),
BypassVideoLengthRestriction(),
MediaQualityLevelOverride(),
MediaUploadQualityOverride(),
MeoPasscodeBypass(),
AppLock(),
CameraTweaks(),

View File

@@ -45,7 +45,7 @@ class ConfigurationOverride : Feature("Configuration Override", loadParams = Fea
overrideProperty("STREAK_EXPIRATION_INFO", { context.config.userInterface.streakExpirationInfo.get() },
{ true })
overrideProperty("TRANSCODING_MAX_QUALITY", { context.config.global.forceUploadSourceQuality.get() },
overrideProperty("TRANSCODING_MAX_QUALITY", { context.config.global.mediaUploadQualityConfig.forceVideoUploadSourceQuality.get() },
{ true }, isAppExperiment = true)
overrideProperty("CAMERA_ME_ENABLE_HEVC_RECORDING", { context.config.camera.hevcRecording.get() },

View File

@@ -1,23 +0,0 @@
package me.rhunk.snapenhance.core.features.impl.global
import me.rhunk.snapenhance.core.features.Feature
import me.rhunk.snapenhance.core.features.FeatureLoadParams
import me.rhunk.snapenhance.core.util.hook.HookStage
import me.rhunk.snapenhance.core.util.hook.hook
import me.rhunk.snapenhance.mapper.impl.MediaQualityLevelProviderMapper
import java.lang.reflect.Method
class MediaQualityLevelOverride : Feature("MediaQualityLevelOverride", loadParams = FeatureLoadParams.INIT_SYNC) {
override fun init() {
if (!context.config.global.forceUploadSourceQuality.get()) return
context.mappings.useMapper(MediaQualityLevelProviderMapper::class) {
mediaQualityLevelProvider.getAsClass()?.hook(
mediaQualityLevelProviderMethod.getAsString()!!,
HookStage.BEFORE
) { param ->
param.setResult((param.method() as Method).returnType.enumConstants.firstOrNull { it.toString() == "LEVEL_MAX" } )
}
}
}
}

View File

@@ -0,0 +1,49 @@
package me.rhunk.snapenhance.core.features.impl.global
import android.graphics.Bitmap
import me.rhunk.snapenhance.core.features.Feature
import me.rhunk.snapenhance.core.features.FeatureLoadParams
import me.rhunk.snapenhance.core.util.hook.HookStage
import me.rhunk.snapenhance.core.util.hook.hook
import me.rhunk.snapenhance.mapper.impl.MediaQualityLevelProviderMapper
import java.lang.reflect.Method
class MediaUploadQualityOverride : Feature("Media Upload Quality Override", loadParams = FeatureLoadParams.INIT_SYNC) {
override fun init() {
if (context.config.global.mediaUploadQualityConfig.forceVideoUploadSourceQuality.get()) {
context.mappings.useMapper(MediaQualityLevelProviderMapper::class) {
mediaQualityLevelProvider.getAsClass()?.hook(
mediaQualityLevelProviderMethod.getAsString()!!,
HookStage.BEFORE
) { param ->
param.setResult((param.method() as Method).returnType.enumConstants.firstOrNull { it.toString() == "LEVEL_MAX" } )
}
}
}
val disableImageCompression by context.config.global.mediaUploadQualityConfig.disableImageCompression
val imageUploadFormat = context.config.global.mediaUploadQualityConfig.customUploadImageFormat.getNullable()
if (imageUploadFormat != null || disableImageCompression) {
Bitmap::class.java.hook("compress", HookStage.BEFORE) { param ->
if (param.arg<Int>(1) == 0) return@hook
if (param.arg<Any>(0) == Bitmap.CompressFormat.JPEG) {
@Suppress("DEPRECATION")
param.setArg(0, when (imageUploadFormat) {
"png" -> Bitmap.CompressFormat.PNG
"webp" -> Bitmap.CompressFormat.WEBP
"jpeg" -> Bitmap.CompressFormat.JPEG
else -> Bitmap.CompressFormat.JPEG
})
if (disableImageCompression) {
param.setArg(1, 100)
}
}
}
findClass("com.snap.camera.jni.SnapImageTranscoder").hook("nativeEncodeBitmapToJpeg", HookStage.BEFORE) {
it.setResult(ByteArray(0))
}
}
}
}