Skip to content

Commit

Permalink
feat(core): spotlight comments username
Browse files Browse the repository at this point in the history
  • Loading branch information
rhunk committed Dec 27, 2023
1 parent 7aa05e9 commit b378bdd
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 0 deletions.
4 changes: 4 additions & 0 deletions common/src/main/assets/lang/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,10 @@
"name": "Block Ads",
"description": "Prevents Advertisements from being displayed"
},
"spotlight_comments_username": {
"name": "Spotlight Comments Username",
"description": "Shows author username in Spotlight comments"
},
"bypass_video_length_restriction": {
"name": "Bypass Video Length Restrictions",
"description": "Single: sends a single video\nSplit: split videos after editing"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class Global : ConfigContainer() {
val disableMetrics = boolean("disable_metrics")
val disablePublicStories = boolean("disable_public_stories") { requireRestart(); requireCleanCache() }
val blockAds = boolean("block_ads")
val spotlightCommentsUsername = boolean("spotlight_comments_username") { requireRestart() }
val bypassVideoLengthRestriction = unique("bypass_video_length_restriction", "split", "single") { addNotices(
FeatureNotice.BAN_RISK); requireRestart(); nativeHooks() }
val disableGooglePlayDialogs = boolean("disable_google_play_dialogs") { requireRestart() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ import me.rhunk.snapenhance.core.util.ktx.getObjectFieldOrNull
import me.rhunk.snapenhance.core.wrapper.impl.ConversationManager
import me.rhunk.snapenhance.core.wrapper.impl.Message
import me.rhunk.snapenhance.core.wrapper.impl.SnapUUID
import me.rhunk.snapenhance.core.wrapper.impl.Snapchatter
import me.rhunk.snapenhance.core.wrapper.impl.toSnapUUID
import java.util.concurrent.Future

class Messaging : Feature("Messaging", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC or FeatureLoadParams.INIT_ASYNC or FeatureLoadParams.INIT_SYNC) {
var conversationManager: ConversationManager? = null
private set
private var conversationManagerDelegate: Any? = null
private var identityDelegate: Any? = null

var openedConversationUUID: SnapUUID? = null
private set
var lastFetchConversationUserUUID: SnapUUID? = null
Expand Down Expand Up @@ -57,6 +61,12 @@ class Messaging : Feature("Messaging", loadParams = FeatureLoadParams.ACTIVITY_C
}
}
}

context.mappings.getMappedClass("callbacks", "IdentityDelegate").apply {
hookConstructor(HookStage.AFTER) {
identityDelegate = it.thisObject()
}
}
}

fun getFeedCachedMessageIds(conversationId: String) = feedCachedSnapMessages[conversationId]
Expand Down Expand Up @@ -169,4 +179,15 @@ class Messaging : Feature("Messaging", loadParams = FeatureLoadParams.ACTIVITY_C
it.setResult(null)
}
}

fun fetchSnapchatterInfos(userIds: List<String>): List<Snapchatter> {
val identity = identityDelegate ?: return emptyList()
val future = identity::class.java.methods.first {
it.name == "fetchSnapchatterInfos"
}.invoke(identity, userIds.map {
it.toSnapUUID().instanceNonNull()
}) as Future<*>

return (future.get() as? List<*>)?.map { Snapchatter(it) } ?: return emptyList()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package me.rhunk.snapenhance.core.features.impl.ui

import android.annotation.SuppressLint
import android.widget.TextView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.rhunk.snapenhance.core.event.events.impl.BindViewEvent
import me.rhunk.snapenhance.core.features.Feature
import me.rhunk.snapenhance.core.features.FeatureLoadParams
import me.rhunk.snapenhance.core.features.impl.messaging.Messaging
import me.rhunk.snapenhance.core.util.EvictingMap
import me.rhunk.snapenhance.core.util.ktx.getId

class SpotlightCommentsUsername : Feature("SpotlightCommentsUsername", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) {
private val usernameCache = EvictingMap<String, String>(150)

@SuppressLint("SetTextI18n")
override fun onActivityCreate() {
if (!context.config.global.spotlightCommentsUsername.get()) return

val messaging = context.feature(Messaging::class)
val commentsCreatorBadgeTimestampId = context.resources.getId("comments_creator_badge_timestamp")

context.event.subscribe(BindViewEvent::class) { event ->
val commentsCreatorBadgeTimestamp = event.view.findViewById<TextView>(commentsCreatorBadgeTimestampId) ?: return@subscribe

val posterUserId = event.prevModel.toString().takeIf { it.startsWith("Comment") }
?.substringAfter("posterUserId=")?.substringBefore(",")?.substringBefore(")") ?: return@subscribe

fun setUsername(username: String) {
usernameCache[posterUserId] = username
commentsCreatorBadgeTimestamp.text = " (${username})" + commentsCreatorBadgeTimestamp.text.toString()
}

usernameCache[posterUserId]?.let {
setUsername(it)
return@subscribe
}

context.coroutineScope.launch {
val username = runCatching {
messaging.fetchSnapchatterInfos(listOf(posterUserId)).firstOrNull()
}.onFailure {
context.log.error("Failed to fetch snapchatter info for user $posterUserId", it)
}.getOrNull()?.username ?: return@launch

withContext(Dispatchers.Main) {
setUsername(username)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class FeatureManager(
PreventForcedLogout::class,
SuspendLocationUpdates::class,
ConversationToolbox::class,
SpotlightCommentsUsername::class,
)

initializeFeatures()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package me.rhunk.snapenhance.core.wrapper.impl

import me.rhunk.snapenhance.core.wrapper.AbstractWrapper



class BitmojiInfo(obj: Any?) : AbstractWrapper(obj) {
var avatarId by field<String?>("mAvatarId")
var backgroundId by field<String?>("mBackgroundId")
var sceneId by field<String?>("mSceneId")
var selfieId by field<String?>("mSelfieId")
}

class Snapchatter(obj: Any?) : AbstractWrapper(obj) {
val bitmojiInfo by field<BitmojiInfo?>("mBitmojiInfo")
var displayName by field<String?>("mDisplayName")
var userId by field("mUserId") { SnapUUID(it) }
var username by field<String>("mUsername")
}

0 comments on commit b378bdd

Please sign in to comment.