feat: process manual channel mentions and emoji shortcodes

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2023-12-03 01:54:37 +01:00
parent 8a935862b0
commit ac31be2a49
3 changed files with 59 additions and 3 deletions

View File

@ -1,14 +1,26 @@
package chat.revolt.api.internals
import chat.revolt.api.RevoltAPI
import chat.revolt.api.schemas.ChannelType
import chat.revolt.internals.EmojiImpl
object MessageProcessor {
private val MentionRegex = Regex("@((?:\\p{L}|[\\d_.-])+)#([0-9]{4})", RegexOption.IGNORE_CASE)
private val ChannelRegex = Regex("(?:\\s|^)#(.+?)(?:\\s|\$)", RegexOption.IGNORE_CASE)
private val EmojiRegex = Regex(":(.+?):", RegexOption.IGNORE_CASE)
fun processOutgoing(content: String): String {
private val emojiMetadata = EmojiImpl()
/**
* Processes an outgoing message for sending.
* 1. Replaces @mentions#0000 with <@userId>
* 2. Replaces #channel with <#channelId> if the current server has a channel with that name
* 2. Replaces :emoji-shortcode: with the emoji's unicode character, if it exists
*/
fun processOutgoing(content: String, serverId: String?): String {
val mentions = MentionRegex.findAll(content).map { it.value }.toList()
return mentions.fold(content) { acc, mention ->
var returnable = mentions.fold(content) { acc, mention ->
val (username, discriminator) = MentionRegex.matchEntire(mention)?.destructured
?: return@fold acc
@ -18,5 +30,34 @@ object MessageProcessor {
val userId = user?.id ?: return@fold acc
acc.replace(mention, "<@$userId>")
}
val channels = ChannelRegex.findAll(returnable).map { it.value }.toList()
returnable = channels.fold(returnable) { acc, channel ->
val channelName = ChannelRegex.matchEntire(channel)?.destructured?.component1()
?: return@fold acc
val fetchedChannel =
RevoltAPI.channelCache.values.find {
it.name == channelName && it.server == serverId && it.channelType == ChannelType.TextChannel
}
?: return@fold acc
fetchedChannel.name?.let { acc.replace("#${it}", "<#${fetchedChannel.id}>") } ?: acc
}
val emojis = EmojiRegex.findAll(returnable).map { it.value }.toList()
returnable = emojis.fold(returnable) { acc, emoji ->
val emojiName = EmojiRegex.matchEntire(emoji)?.destructured?.component1()
?: return@fold acc
val byShortcode = emojiMetadata.unicodeByShortcode(emojiName)
?: return@fold acc
acc.replace(":$emojiName:", byShortcode)
}
return returnable
}
}

View File

@ -247,6 +247,18 @@ class EmojiImpl {
return list
}
fun unicodeByShortcode(shortcode: String): String? {
return metadata.asSequence().mapNotNull { group ->
group.emoji.find { emoji ->
emoji.shortcodes.any { code ->
code == ":${shortcode}:"
}
}
}.firstOrNull().let { emoji ->
emoji?.base?.joinToString("") { String(Character.toChars(it.toInt())) }
}
}
init {
metadata = initMetadata(RevoltApplication.instance.applicationContext)
}

View File

@ -212,7 +212,10 @@ class ChannelScreenViewModel : ViewModel() {
sendMessage(
activeChannel!!.id!!,
MessageProcessor.processOutgoing(pendingMessageContent.trimIndent()),
MessageProcessor.processOutgoing(
pendingMessageContent.trimIndent(),
activeChannel?.server
),
attachments = if (attachmentIds.isEmpty()) null else attachmentIds,
replies = pendingReplies
)