Skip to content

Commit

Permalink
Add a function for parsing a channel ID from a channel URL (#3075)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
TheCataliasTNT2k authored Dec 8, 2024
1 parent 6901986 commit d7c5ee3
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/utils/argument_convert/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ async fn lookup_channel_global(
guild_id: Option<GuildId>,
s: &str,
) -> Result<Channel, ChannelParseError> {
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);
}

Expand Down
38 changes: 38 additions & 0 deletions src/utils/argument_convert/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<MAX_DOMAIN_LEN>(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;
Expand Down

0 comments on commit d7c5ee3

Please sign in to comment.