diff --git a/core/api/core.api b/core/api/core.api index 19c163b67c2..3560eb402e0 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -62,6 +62,7 @@ public final class dev/kord/core/Kord : kotlinx/coroutines/CoroutineScope { public static synthetic fun getInvite$default (Ldev/kord/core/Kord;Ljava/lang/String;ZZLdev/kord/common/entity/Snowflake;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; public final fun getInviteOrNull (Ljava/lang/String;ZZLdev/kord/common/entity/Snowflake;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun getInviteOrNull$default (Ldev/kord/core/Kord;Ljava/lang/String;ZZLdev/kord/common/entity/Snowflake;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public final fun getMessageByLink (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun getNitroStickerPacks ()Lkotlinx/coroutines/flow/Flow; public final fun getRegions ()Lkotlinx/coroutines/flow/Flow; public final fun getResources ()Ldev/kord/core/ClientResources; diff --git a/core/api/core.klib.api b/core/api/core.klib.api index d7aa07aa4db..10df4d5c9e9 100644 --- a/core/api/core.klib.api +++ b/core/api/core.klib.api @@ -9274,6 +9274,7 @@ final class dev.kord.core/Kord : kotlinx.coroutines/CoroutineScope { // dev.kord final suspend fun getGuildPreviewOrNull(dev.kord.common.entity/Snowflake, dev.kord.core.supplier/EntitySupplyStrategy<*> = ...): dev.kord.core.entity/GuildPreview? // dev.kord.core/Kord.getGuildPreviewOrNull|getGuildPreviewOrNull(dev.kord.common.entity.Snowflake;dev.kord.core.supplier.EntitySupplyStrategy<*>){}[0] final suspend fun getInvite(kotlin/String, kotlin/Boolean = ..., kotlin/Boolean = ..., dev.kord.common.entity/Snowflake? = ...): dev.kord.core.entity/Invite // dev.kord.core/Kord.getInvite|getInvite(kotlin.String;kotlin.Boolean;kotlin.Boolean;dev.kord.common.entity.Snowflake?){}[0] final suspend fun getInviteOrNull(kotlin/String, kotlin/Boolean = ..., kotlin/Boolean = ..., dev.kord.common.entity/Snowflake? = ...): dev.kord.core.entity/Invite? // dev.kord.core/Kord.getInviteOrNull|getInviteOrNull(kotlin.String;kotlin.Boolean;kotlin.Boolean;dev.kord.common.entity.Snowflake?){}[0] + final suspend fun getMessageByLink(kotlin/String): dev.kord.core.entity/Message? // dev.kord.core/Kord.getMessageByLink|getMessageByLink(kotlin.String){}[0] final suspend fun getSelf(dev.kord.core.supplier/EntitySupplyStrategy<*> = ...): dev.kord.core.entity/User // dev.kord.core/Kord.getSelf|getSelf(dev.kord.core.supplier.EntitySupplyStrategy<*>){}[0] final suspend fun getSticker(dev.kord.common.entity/Snowflake): dev.kord.core.entity/Sticker // dev.kord.core/Kord.getSticker|getSticker(dev.kord.common.entity.Snowflake){}[0] final suspend fun getUser(dev.kord.common.entity/Snowflake, dev.kord.core.supplier/EntitySupplyStrategy<*> = ...): dev.kord.core.entity/User? // dev.kord.core/Kord.getUser|getUser(dev.kord.common.entity.Snowflake;dev.kord.core.supplier.EntitySupplyStrategy<*>){}[0] diff --git a/core/src/commonMain/kotlin/Kord.kt b/core/src/commonMain/kotlin/Kord.kt index f116b1b2571..2e1fc9c37d8 100644 --- a/core/src/commonMain/kotlin/Kord.kt +++ b/core/src/commonMain/kotlin/Kord.kt @@ -6,6 +6,7 @@ import dev.kord.common.annotation.KordUnsafe import dev.kord.common.entity.DiscordShard import dev.kord.common.entity.Snowflake import dev.kord.common.exception.RequestException +import dev.kord.core.behavior.channel.asChannelOfOrNull import dev.kord.core.builder.kord.KordBuilder import dev.kord.core.builder.kord.KordProxyBuilder import dev.kord.core.builder.kord.KordRestOnlyBuilder @@ -15,6 +16,7 @@ import dev.kord.core.cache.data.UserData import dev.kord.core.entity.* import dev.kord.core.entity.application.* import dev.kord.core.entity.channel.Channel +import dev.kord.core.entity.channel.MessageChannel import dev.kord.core.event.Event import dev.kord.core.exception.EntityNotFoundException import dev.kord.core.exception.KordInitializationException @@ -43,6 +45,18 @@ import kotlinx.coroutines.channels.Channel as CoroutineChannel public val kordLogger: mu.KLogger = mu.KotlinLogging.logger { } private val logger = KotlinLogging.logger { } +private val messageLinkRegex = """ + |(?x) # enable comments + |(?i) # allow ignore case + |(?:https?+://)?+ # https:// (or also http:// or an empty string) + |(?:(?:canary|ptb)\.)?+ # canary. or ptb. + |discord(?:app)?+\.com/channels/ # discord(app).com/channels/ + |(?:(?[0-9]++)|@me) # @me or the server id + |/ # '/' + |(?[0-9]++) # the channel id (should only be a message channel) + |/ # '/' + |(?[0-9]++) # the message id + """.trimMargin().toRegex() @PublishedApi internal fun logCaughtThrowable(throwable: Throwable): Unit = logger.catching(throwable) @@ -258,6 +272,27 @@ public class Kord( strategy: EntitySupplyStrategy<*> = resources.defaultStrategy, ): Guild = strategy.supply(this).getGuild(id) + /** + * Returns the [Message] that is fetched by the given [messageLink]. + * If either the channel or the message id found in the link is invalid, null is returned. + * + * @throws IllegalArgumentException if the message link doesn't match the format found in [messageLinkRegex] + */ + public suspend fun getMessageByLink( + messageLink: String + ): Message? { + val matches = messageLinkRegex.matchEntire(messageLink) + + require(matches != null) { "The message link has an invalid format." } + + val channel = matches.groups["channel"]?.value + ?.let { getChannel(Snowflake(it)) } + ?.asChannelOfOrNull() + + return matches.groups["message"]?.value + ?.let { channel?.getMessageOrNull(Snowflake(it)) } + } + /** * Requests to get the [Webhook] in this guild. *