Skip to content

Commit

Permalink
Add a function for parsing a channel ID from a channel URL (serenity-…
Browse files Browse the repository at this point in the history
…rs#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.
  • Loading branch information
TheCataliasTNT2k authored and mkrasnitski committed Dec 8, 2024
1 parent f7daa0f commit 7e90b9d
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 7e90b9d

Please sign in to comment.