From 7e90b9ddaf65109b1e88dbafa721daa148f77590 Mon Sep 17 00:00:00 2001 From: TheCataliasTNT2k <44349750+TheCataliasTNT2k@users.noreply.github.com> Date: Sun, 8 Dec 2024 15:36:59 +0100 Subject: [PATCH] Add a function for parsing a channel ID from a channel URL (#3075) Similar to message URLs, Discord also provides URLs for guild channels. Additionally, the function is added as an alternative for parsing a `Channel` from a string. Private channels are not affected by this change. --- src/utils/argument_convert/channel.rs | 7 ++++- src/utils/argument_convert/mod.rs | 38 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/utils/argument_convert/channel.rs b/src/utils/argument_convert/channel.rs index e94879e5e4c..debba293bf7 100644 --- a/src/utils/argument_convert/channel.rs +++ b/src/utils/argument_convert/channel.rs @@ -45,7 +45,12 @@ async fn lookup_channel_global( guild_id: Option, s: &str, ) -> Result { - if let Some(channel_id) = s.parse().ok().or_else(|| crate::utils::parse_channel_mention(s)) { + if let Some(channel_id) = s + .parse() + .ok() + .or_else(|| crate::utils::parse_channel_mention(s)) + .or_else(|| crate::utils::parse_channel_url(s).map(|(_, channel_id)| channel_id)) + { return channel_id.to_channel(ctx, guild_id).await.map_err(ChannelParseError::Http); } diff --git a/src/utils/argument_convert/mod.rs b/src/utils/argument_convert/mod.rs index bbe118a34d7..8a43f726a69 100644 --- a/src/utils/argument_convert/mod.rs +++ b/src/utils/argument_convert/mod.rs @@ -140,6 +140,44 @@ pub fn parse_message_url(s: &str) -> Option<(GuildId, ChannelId, MessageId)> { None } +/// Retrieves guild, and channel ID from a channel URL. +/// +/// If the URL is malformed, None is returned. +/// +/// # Examples +/// ```rust +/// use serenity::model::prelude::*; +/// use serenity::utils::parse_channel_url; +/// +/// assert_eq!( +/// parse_channel_url("https://discord.com/channels/381880193251409931/381880193700069377"), +/// Some((GuildId::new(381880193251409931), ChannelId::new(381880193700069377),)), +/// ); +/// assert_eq!( +/// parse_channel_url( +/// "https://canary.discord.com/channels/381880193251409931/381880193700069377" +/// ), +/// Some((GuildId::new(381880193251409931), ChannelId::new(381880193700069377),)), +/// ); +/// assert_eq!(parse_channel_url("https://google.com"), None); +/// ``` +#[must_use] +pub fn parse_channel_url(s: &str) -> Option<(GuildId, ChannelId)> { + use aformat::{aformat, CapStr}; + + for domain in DOMAINS { + let prefix = aformat!("https://{}/channels/", CapStr::(domain)); + if let Some(parts) = s.strip_prefix(prefix.as_str()) { + let mut parts = parts.splitn(2, '/'); + + let guild_id = parts.next()?.parse().ok()?; + let channel_id = parts.next()?.parse().ok()?; + return Some((guild_id, channel_id)); + } + } + None +} + const MAX_DOMAIN_LEN: usize = { let mut max_len = 0; let mut i = 0;