Skip to content

Commit

Permalink
[Feature] Media channel support (#2725)
Browse files Browse the repository at this point in the history
* initial commit

* oops

* another typo -_-

* Update AttachmentFlags.cs

Made this on my phone lol

* Update AttachmentFlags.cs

* -line

* initial impl

* some guild methods for media (and forum) channels

* file attachment can be a thumbnail

* can't edit media channel layout

* updatess

* Update ChannelPermissions.cs

* typo
  • Loading branch information
Misha-133 committed Nov 18, 2023
1 parent 9cedfbc commit e3cd340
Show file tree
Hide file tree
Showing 22 changed files with 468 additions and 52 deletions.
9 changes: 7 additions & 2 deletions src/Discord.Net.Core/Entities/Channels/ChannelFlags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ public enum ChannelFlags
Pinned = 1 << 1,

/// <summary>
/// Flag given to a forum channel that requires people to select tags when posting.
/// Flag given to a forum or media channel that requires people to select tags when posting.
/// </summary>
RequireTag = 1 << 4
RequireTag = 1 << 4,

/// <summary>
/// Flag given to a media channel that hides the embedded media download options.
/// </summary>
HideMediaDownloadOption = 1 << 15,
}
104 changes: 73 additions & 31 deletions src/Discord.Net.Core/Entities/Channels/ChannelType.cs
Original file line number Diff line number Diff line change
@@ -1,33 +1,75 @@
namespace Discord
namespace Discord;

/// <summary> Defines the types of channels. </summary>
public enum ChannelType
{
/// <summary> Defines the types of channels. </summary>
public enum ChannelType
{
/// <summary> The channel is a text channel. </summary>
Text = 0,
/// <summary> The channel is a Direct Message channel. </summary>
DM = 1,
/// <summary> The channel is a voice channel. </summary>
Voice = 2,
/// <summary> The channel is a group channel. </summary>
Group = 3,
/// <summary> The channel is a category channel. </summary>
Category = 4,
/// <summary> The channel is a news channel. </summary>
News = 5,
/// <summary> The channel is a store channel. </summary>
Store = 6,
/// <summary> The channel is a temporary thread channel under a news channel. </summary>
NewsThread = 10,
/// <summary> The channel is a temporary thread channel under a text channel. </summary>
PublicThread = 11,
/// <summary> The channel is a private temporary thread channel under a text channel. </summary>
PrivateThread = 12,
/// <summary> The channel is a stage voice channel. </summary>
Stage = 13,
/// <summary> The channel is a guild directory used in hub servers. (Unreleased)</summary>
GuildDirectory = 14,
/// <summary> The channel is a forum channel containing multiple threads. </summary>
Forum = 15
}
/// <summary>
/// The channel is a text channel.
/// </summary>
Text = 0,

/// <summary>
/// The channel is a Direct Message channel.
/// </summary>
DM = 1,

/// <summary>
/// The channel is a voice channel.
/// </summary>
Voice = 2,

/// <summary>
/// The channel is a group channel.
/// </summary>
Group = 3,

/// <summary>
/// The channel is a category channel.
/// </summary>
Category = 4,

/// <summary>
/// The channel is a news channel.
/// </summary>
News = 5,

/// <summary>
/// The channel is a store channel.
/// </summary>
Store = 6,

/// <summary>
/// The channel is a temporary thread channel under a news channel.
/// </summary>
NewsThread = 10,

/// <summary>
/// The channel is a temporary thread channel under a text channel.
/// </summary>
PublicThread = 11,

/// <summary>
/// The channel is a private temporary thread channel under a text channel.
/// </summary>
PrivateThread = 12,

/// <summary>
/// The channel is a stage voice channel.
/// </summary>
Stage = 13,

/// <summary>
/// The channel is a guild directory used in hub servers. (Unreleased)
/// </summary>
GuildDirectory = 14,

/// <summary>
/// The channel is a forum channel containing multiple threads.
/// </summary>
Forum = 15,

/// <summary>
/// The channel is a media channel containing multiple threads.
/// </summary>
Media = 16,
}
11 changes: 7 additions & 4 deletions src/Discord.Net.Core/Entities/Channels/ForumChannelProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,25 @@ public class ForumChannelProperties : TextChannelProperties
public Optional<int> ThreadCreationInterval { get; set; }

/// <summary>
/// Gets or sets a collection of tags inside of this forum channel.
/// Gets or sets a collection of tags inside of this forum channel.
/// </summary>
public Optional<IEnumerable<IForumTag>> Tags { get; set; }

/// <summary>
/// Gets or sets a new default reaction emoji in this forum channel.
/// Gets or sets a new default reaction emoji in this forum channel.
/// </summary>
public Optional<IEmote> DefaultReactionEmoji { get; set; }

/// <summary>
/// Gets or sets the rule used to order posts in forum channels.
/// Gets or sets the rule used to order posts in forum channels.
/// </summary>
public Optional<ForumSortOrder> DefaultSortOrder { get; set; }

/// <summary>
/// Gets or sets the rule used to display posts in a forum channel.
/// Gets or sets the rule used to display posts in a forum channel.
/// </summary>
/// <remarks>
/// This property cannot be changed in media channels.
/// </remarks>
public Optional<ForumLayout> DefaultLayout { get; set; }
}
9 changes: 9 additions & 0 deletions src/Discord.Net.Core/Entities/Channels/IMediaChannel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Discord;

/// <summary>
/// Represents a media channel in a guild that can create posts.
/// </summary>
public interface IMediaChannel : IForumChannel
{

}
58 changes: 58 additions & 0 deletions src/Discord.Net.Core/Entities/Guilds/IGuild.cs
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,52 @@ public interface IGuild : IDeletable, ISnowflakeEntity
/// </returns>
Task<IReadOnlyCollection<IThreadChannel>> GetThreadChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);

/// <summary>
/// Gets a forum channel in this guild.
/// </summary>
/// <param name="id">The snowflake identifier for the stage channel.</param>
/// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the stage channel associated
/// with the specified <paramref name="id"/>; <see langword="null" /> if none is found.
/// </returns>
Task<IForumChannel> GetForumChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);

/// <summary>
/// Gets a collection of all forum channels in this guild.
/// </summary>
/// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection of
/// forum channels found within this guild.
/// </returns>
Task<IReadOnlyCollection<IForumChannel>> GetForumChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);

/// <summary>
/// Gets a forum channel in this guild.
/// </summary>
/// <param name="id">The snowflake identifier for the stage channel.</param>
/// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the stage channel associated
/// with the specified <paramref name="id"/>; <see langword="null" /> if none is found.
/// </returns>
Task<IMediaChannel> GetMediaChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);

/// <summary>
/// Gets a collection of all forum channels in this guild.
/// </summary>
/// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection of
/// media channels found within this guild.
/// </returns>
Task<IReadOnlyCollection<IMediaChannel>> GetMediaChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);

/// <summary>
/// Creates a new text channel in this guild.
/// </summary>
Expand Down Expand Up @@ -795,6 +841,18 @@ public interface IGuild : IDeletable, ISnowflakeEntity
/// </returns>
Task<IForumChannel> CreateForumChannelAsync(string name, Action<ForumChannelProperties> func = null, RequestOptions options = null);

/// <summary>
/// Creates a new media channel in this guild.
/// </summary>
/// <param name="name">The new name for the media channel.</param>
/// <param name="func">The delegate containing the properties to be applied to the channel upon its creation.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains the newly created
/// forum channel.
/// </returns>
Task<IMediaChannel> CreateMediaChannelAsync(string name, Action<ForumChannelProperties> func = null, RequestOptions options = null);

/// <summary>
/// Gets a collection of all the voice regions this guild can access.
/// </summary>
Expand Down
17 changes: 11 additions & 6 deletions src/Discord.Net.Core/Entities/Messages/FileAttachment.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord
{
Expand All @@ -26,6 +22,11 @@ public struct FileAttachment : IDisposable
/// </summary>
public bool IsSpoiler { get; set; }

/// <summary>
/// Gets or sets if this file should be a thumbnail for a media channel post.
/// </summary>
public bool IsThumbnail { get; set; }

#pragma warning disable IDISP008
/// <summary>
/// Gets the stream containing the file content.
Expand All @@ -42,12 +43,14 @@ public struct FileAttachment : IDisposable
/// <param name="fileName">The name of the attachment.</param>
/// <param name="description">The description of the attachment.</param>
/// <param name="isSpoiler">Whether or not the attachment is a spoiler.</param>
public FileAttachment(Stream stream, string fileName, string description = null, bool isSpoiler = false)
/// <param name="isThumbnail">Whether or not this attachment should be a thumbnail for a media channel post.</param>
public FileAttachment(Stream stream, string fileName, string description = null, bool isSpoiler = false, bool isThumbnail = false)
{
_isDisposed = false;
FileName = fileName;
Description = description;
Stream = stream;
IsThumbnail = isThumbnail;
try
{
Stream.Position = 0;
Expand All @@ -67,6 +70,7 @@ public FileAttachment(Stream stream, string fileName, string description = null,
/// <param name="fileName">The name of the attachment.</param>
/// <param name="description">The description of the attachment.</param>
/// <param name="isSpoiler">Whether or not the attachment is a spoiler.</param>
/// <param name="isThumbnail">Whether or not this attachment should be a thumbnail for a media channel post.</param>
/// <exception cref="System.ArgumentException">
/// <paramref name="path" /> is a zero-length string, contains only white space, or contains one or more invalid
/// characters as defined by <see cref="Path.GetInvalidPathChars"/>.
Expand All @@ -87,13 +91,14 @@ public FileAttachment(Stream stream, string fileName, string description = null,
/// <exception cref="FileNotFoundException">The file specified in <paramref name="path" /> was not found.
/// </exception>
/// <exception cref="IOException">An I/O error occurred while opening the file. </exception>
public FileAttachment(string path, string fileName = null, string description = null, bool isSpoiler = false)
public FileAttachment(string path, string fileName = null, string description = null, bool isSpoiler = false, bool isThumbnail = false)
{
_isDisposed = false;
Stream = File.OpenRead(path);
FileName = fileName ?? Path.GetFileName(path);
Description = description;
IsSpoiler = isSpoiler;
IsThumbnail = isThumbnail;
}

public void Dispose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public struct ChannelPermissions
/// </summary>
public static readonly ChannelPermissions Forum = new(0b01_001110_010010_110011_111101_111111_111101_010001);

/// <summary>
/// Gets a <see cref="ChannelPermissions"/> that grants all permissions for media channels.
/// </summary>
public static readonly ChannelPermissions Media = new(0b01_001110_010010_110011_111101_111111_111101_010001);

/// <summary>
/// Gets a <see cref="ChannelPermissions"/> that grants all permissions for a given channel type.
/// </summary>
Expand All @@ -64,6 +69,7 @@ public static ChannelPermissions All(IChannel channel)
ICategoryChannel _ => Category,
IDMChannel _ => DM,
IGroupChannel _ => Group,
IMediaChannel _ => Media,
IForumChannel => Forum,
_ => throw new ArgumentException(message: "Unknown channel type.", paramName: nameof(channel)),
};
Expand Down
3 changes: 3 additions & 0 deletions src/Discord.Net.Core/Extensions/ChannelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public static class ChannelExtensions
case ITextChannel:
return ChannelType.Text;

case IMediaChannel:
return ChannelType.Media;

case IForumChannel:
return ChannelType.Forum;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Discord.Net.Core/Utils/ChannelTypeUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ public static List<ChannelType> AllChannelTypes()
{
ChannelType.Forum, ChannelType.Category, ChannelType.DM, ChannelType.Group, ChannelType.GuildDirectory,
ChannelType.News, ChannelType.NewsThread, ChannelType.PrivateThread, ChannelType.PublicThread,
ChannelType.Stage, ChannelType.Store, ChannelType.Text, ChannelType.Voice
ChannelType.Stage, ChannelType.Store, ChannelType.Text, ChannelType.Voice, ChannelType.Media
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ _ when typeof(IThreadChannel).IsAssignableFrom(type)
_ when typeof(ITextChannel).IsAssignableFrom(type)
=> new List<ChannelType> { ChannelType.Text },

_ when typeof(IMediaChannel).IsAssignableFrom(type)
=> new List<ChannelType> { ChannelType.Media },

_ when typeof(IForumChannel).IsAssignableFrom(type)
=> new List<ChannelType> { ChannelType.Forum },

_ => null
};
}
Expand Down
3 changes: 2 additions & 1 deletion src/Discord.Net.Rest/API/Rest/CreateMultipartPostAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ public IReadOnlyDictionary<string, object> ToDictionary()
{
id = (ulong)n,
filename = filename,
description = attachment.Description ?? Optional<string>.Unspecified
description = attachment.Description ?? Optional<string>.Unspecified,
is_thumbnail = attachment.IsThumbnail,
});
}

Expand Down
3 changes: 1 addition & 2 deletions src/Discord.Net.Rest/Entities/Channels/ForumHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ public static async Task<Model> ModifyAsync(IForumChannel channel, BaseDiscordCl
emoji.Name : Optional<string>.Unspecified
}
: Optional<ModifyForumReactionEmojiParams>.Unspecified,
DefaultSortOrder = args.DefaultSortOrder,
DefaultLayout = args.DefaultLayout,
DefaultSortOrder = args.DefaultSortOrder
};
return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false);
}
Expand Down
3 changes: 2 additions & 1 deletion src/Discord.Net.Rest/Entities/Channels/RestChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ ChannelType.Stage or
ChannelType.NewsThread or
ChannelType.PrivateThread or
ChannelType.PublicThread or
ChannelType.Forum
ChannelType.Forum or
ChannelType.Media
=> RestGuildChannel.Create(discord, guild, model),
ChannelType.DM or ChannelType.Group => CreatePrivate(discord, model) as RestChannel,
ChannelType.Category => RestCategoryChannel.Create(discord, guild, model),
Expand Down
1 change: 1 addition & 0 deletions src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ internal static RestGuildChannel Create(BaseDiscordClient discord, IGuild guild,
ChannelType.Text => RestTextChannel.Create(discord, guild, model),
ChannelType.Voice => RestVoiceChannel.Create(discord, guild, model),
ChannelType.Stage => RestStageChannel.Create(discord, guild, model),
ChannelType.Media => RestMediaChannel.Create(discord, guild, model),
ChannelType.Forum => RestForumChannel.Create(discord, guild, model),
ChannelType.Category => RestCategoryChannel.Create(discord, guild, model),
ChannelType.PublicThread or ChannelType.PrivateThread or ChannelType.NewsThread => RestThreadChannel.Create(discord, guild, model),
Expand Down
Loading

0 comments on commit e3cd340

Please sign in to comment.