diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml
index 989f35ec1..f60adb42c 100644
--- a/src/Discord.Net.Core/Discord.Net.Core.xml
+++ b/src/Discord.Net.Core/Discord.Net.Core.xml
@@ -3945,6 +3945,33 @@
A task that represents the asynchronous creation operation. The task result contains the created sticker.
+
+
+ Creates a new sticker in this guild
+
+ The name of the sticker.
+ The description of the sticker.
+ The tags of the sticker.
+ The path of the file to upload.
+ The options to be used when sending the request.
+
+ A task that represents the asynchronous creation operation. The task result contains the created sticker.
+
+
+
+
+ Creates a new sticker in this guild
+
+ The name of the sticker.
+ The description of the sticker.
+ The tags of the sticker.
+ The stream containing the file data.
+ The name of the file with the extension, ex: image.png
+ The options to be used when sending the request.
+
+ A task that represents the asynchronous creation operation. The task result contains the created sticker.
+
+
Gets a specific sticker within this guild.
diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs
index d9daf80cd..314e7e6c3 100644
--- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs
+++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs
@@ -2,6 +2,7 @@ using Discord.Audio;
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.IO;
using System.Threading.Tasks;
namespace Discord
@@ -962,6 +963,33 @@ namespace Discord
///
Task CreateStickerAsync(string name, string description, IEnumerable tags, Image image, RequestOptions options = null);
+ ///
+ /// Creates a new sticker in this guild
+ ///
+ /// The name of the sticker.
+ /// The description of the sticker.
+ /// The tags of the sticker.
+ /// The path of the file to upload.
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous creation operation. The task result contains the created sticker.
+ ///
+ Task CreateStickerAsync(string name, string description, IEnumerable tags, string path, RequestOptions options = null);
+
+ ///
+ /// Creates a new sticker in this guild
+ ///
+ /// The name of the sticker.
+ /// The description of the sticker.
+ /// The tags of the sticker.
+ /// The stream containing the file data.
+ /// The name of the file with the extension, ex: image.png
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous creation operation. The task result contains the created sticker.
+ ///
+ Task CreateStickerAsync(string name, string description, IEnumerable tags, Stream stream, string filename, RequestOptions options = null);
+
///
/// Gets a specific sticker within this guild.
///
diff --git a/src/Discord.Net.Rest/API/Net/MultipartFile.cs b/src/Discord.Net.Rest/API/Net/MultipartFile.cs
index 604852e90..ab28c0dbc 100644
--- a/src/Discord.Net.Rest/API/Net/MultipartFile.cs
+++ b/src/Discord.Net.Rest/API/Net/MultipartFile.cs
@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
namespace Discord.Net.Rest
{
@@ -6,11 +6,13 @@ namespace Discord.Net.Rest
{
public Stream Stream { get; }
public string Filename { get; }
+ public string ContentType { get; }
- public MultipartFile(Stream stream, string filename)
+ public MultipartFile(Stream stream, string filename, string contentType = null)
{
Stream = stream;
Filename = filename;
+ this.ContentType = contentType;
}
}
}
diff --git a/src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs b/src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs
index be9cb05f0..405d3e04e 100644
--- a/src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs
+++ b/src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs
@@ -15,17 +15,25 @@ namespace Discord.API.Rest
public string Name { get; set; }
public string Description { get; set; }
public string Tags { get; set; }
+ public string FileName { get; set; }
public IReadOnlyDictionary ToDictionary()
{
var d = new Dictionary();
- d["file"] = new MultipartFile(File, Name + ".dat");
-
- d["name"] = Name;
+ d["name"] = $"{Name}";
d["description"] = Description;
d["tags"] = Tags;
+ string contentType = "image/png";
+
+ if (File is FileStream fileStream)
+ contentType = $"image/{Path.GetExtension(fileStream.Name)}";
+ else if(FileName != null)
+ contentType = $"image/{Path.GetExtension(FileName)}";
+
+ d["file"] = new MultipartFile(File, FileName ?? "image", contentType.Replace(".", ""));
+
return d;
}
}
diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.xml b/src/Discord.Net.Rest/Discord.Net.Rest.xml
index 4cb5f6e02..2c53beefc 100644
--- a/src/Discord.Net.Rest/Discord.Net.Rest.xml
+++ b/src/Discord.Net.Rest/Discord.Net.Rest.xml
@@ -3540,6 +3540,33 @@
A task that represents the asynchronous creation operation. The task result contains the created sticker.
+
+
+ Creates a new sticker in this guild
+
+ The name of the sticker.
+ The description of the sticker.
+ The tags of the sticker.
+ The path of the file to upload.
+ The options to be used when sending the request.
+
+ A task that represents the asynchronous creation operation. The task result contains the created sticker.
+
+
+
+
+ Creates a new sticker in this guild
+
+ The name of the sticker.
+ The description of the sticker.
+ The tags of the sticker.
+ The stream containing the file data.
+ The name of the file with the extension, ex: image.png
+ The options to be used when sending the request.
+
+ A task that represents the asynchronous creation operation. The task result contains the created sticker.
+
+
Gets a specific sticker within this guild.
@@ -3707,6 +3734,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
index bedb9de2f..b1fb2f044 100644
--- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
+++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
@@ -8,6 +8,7 @@ using WidgetModel = Discord.API.GuildWidget;
using Model = Discord.API.Guild;
using RoleModel = Discord.API.Role;
using ImageModel = Discord.API.Image;
+using System.IO;
namespace Discord.Rest
{
@@ -559,6 +560,32 @@ namespace Discord.Rest
return await client.ApiClient.CreateGuildStickerAsync(apiArgs, guild.Id, options).ConfigureAwait(false);
}
+ public static async Task CreateStickerAsync(BaseDiscordClient client, IGuild guild, string name, string description, IEnumerable tags,
+ Stream file, string filename, RequestOptions options = null)
+ {
+ Preconditions.NotNull(name, nameof(name));
+ Preconditions.NotNull(description, nameof(description));
+ Preconditions.NotNull(file, nameof(file));
+ Preconditions.NotNull(filename, nameof(filename));
+
+ Preconditions.AtLeast(name.Length, 2, nameof(name));
+ Preconditions.AtLeast(description.Length, 2, nameof(description));
+
+ Preconditions.AtMost(name.Length, 30, nameof(name));
+ Preconditions.AtMost(description.Length, 100, nameof(name));
+
+ var apiArgs = new CreateStickerParams()
+ {
+ Name = name,
+ Description = description,
+ File = file,
+ Tags = string.Join(", ", tags),
+ FileName = filename
+ };
+
+ return await client.ApiClient.CreateGuildStickerAsync(apiArgs, guild.Id, options).ConfigureAwait(false);
+ }
+
public static async Task ModifyStickerAsync(BaseDiscordClient client, ulong guildId, ISticker sticker, Action func,
RequestOptions options = null)
{
diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
index e87e24b25..b27bcd996 100644
--- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
+++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Threading.Tasks;
using WidgetModel = Discord.API.GuildWidget;
using Model = Discord.API.Guild;
+using System.IO;
namespace Discord.Rest
{
@@ -946,6 +947,42 @@ namespace Discord.Rest
return CustomSticker.Create(Discord, model, this, model.User.IsSpecified ? model.User.Value.Id : null);
}
///
+ /// Creates a new sticker in this guild
+ ///
+ /// The name of the sticker.
+ /// The description of the sticker.
+ /// The tags of the sticker.
+ /// The path of the file to upload.
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous creation operation. The task result contains the created sticker.
+ ///
+ public Task CreateStickerAsync(string name, string description, IEnumerable tags, string path,
+ RequestOptions options = null)
+ {
+ var fs = File.OpenRead(path);
+ return CreateStickerAsync(name, description, tags, fs, Path.GetFileName(fs.Name), options);
+ }
+ ///
+ /// Creates a new sticker in this guild
+ ///
+ /// The name of the sticker.
+ /// The description of the sticker.
+ /// The tags of the sticker.
+ /// The stream containing the file data.
+ /// The name of the file with the extension, ex: image.png
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous creation operation. The task result contains the created sticker.
+ ///
+ public async Task CreateStickerAsync(string name, string description, IEnumerable tags, Stream stream,
+ string filename, RequestOptions options = null)
+ {
+ var model = await GuildHelper.CreateStickerAsync(Discord, this, name, description, tags, stream, filename, options).ConfigureAwait(false);
+
+ return CustomSticker.Create(Discord, model, this, model.User.IsSpecified ? model.User.Value.Id : null);
+ }
+ ///
/// Gets a specific sticker within this guild.
///
/// The id of the sticker to get.
@@ -1262,8 +1299,16 @@ namespace Discord.Rest
///
async Task> IGuild.GetApplicationCommandsAsync (RequestOptions options)
=> await GetApplicationCommandsAsync(options).ConfigureAwait(false);
+ ///
async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, Image image, RequestOptions options)
=> await CreateStickerAsync(name, description, tags, image, options);
+ ///
+ async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, Stream stream, string filename, RequestOptions options)
+ => await CreateStickerAsync(name, description, tags, stream, filename, options);
+ ///
+ async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, string path, RequestOptions options)
+ => await CreateStickerAsync(name, description, tags, path, options);
+ ///
async Task IGuild.GetStickerAsync(ulong id, CacheMode mode, RequestOptions options)
{
if (mode != CacheMode.AllowDownload)
@@ -1271,6 +1316,7 @@ namespace Discord.Rest
return await GetStickerAsync(id, options);
}
+ ///
async Task> IGuild.GetStickersAsync(CacheMode mode, RequestOptions options)
{
if (mode != CacheMode.AllowDownload)
@@ -1278,6 +1324,7 @@ namespace Discord.Rest
return await GetStickersAsync(options);
}
+ ///
Task IGuild.DeleteStickerAsync(ICustomSticker sticker, RequestOptions options)
=> sticker.DeleteAsync();
}
diff --git a/src/Discord.Net.Rest/Net/DefaultRestClient.cs b/src/Discord.Net.Rest/Net/DefaultRestClient.cs
index b5036d94e..62ebd6d78 100644
--- a/src/Discord.Net.Rest/Net/DefaultRestClient.cs
+++ b/src/Discord.Net.Rest/Net/DefaultRestClient.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
+using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -101,7 +102,7 @@ namespace Discord.Net.Rest
switch (p.Value)
{
#pragma warning disable IDISP004
- case string stringValue: { content.Add(new StringContent(stringValue), p.Key); continue; }
+ case string stringValue: { content.Add(new StringContent(stringValue, Encoding.UTF8, "text/plain"), p.Key); continue; }
case byte[] byteArrayValue: { content.Add(new ByteArrayContent(byteArrayValue), p.Key); continue; }
case Stream streamValue: { content.Add(new StreamContent(streamValue), p.Key); continue; }
case MultipartFile fileValue:
@@ -116,8 +117,16 @@ namespace Discord.Net.Rest
stream = memoryStream;
#pragma warning restore IDISP001
}
- content.Add(new StreamContent(stream), p.Key, fileValue.Filename);
+
+ var streamContent = new StreamContent(stream);
+ var extension = fileValue.Filename.Split('.').Last();
+
+ if(fileValue.ContentType != null)
+ streamContent.Headers.ContentType = new MediaTypeHeaderValue(fileValue.ContentType);
+
+ content.Add(streamContent, p.Key, fileValue.Filename);
#pragma warning restore IDISP004
+
continue;
}
default: throw new InvalidOperationException($"Unsupported param type \"{p.Value.GetType().Name}\".");
diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
index 390bc0512..205642634 100644
--- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
+++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
@@ -20,6 +20,7 @@ using RoleModel = Discord.API.Role;
using UserModel = Discord.API.User;
using VoiceStateModel = Discord.API.VoiceState;
using StickerModel = Discord.API.Sticker;
+using System.IO;
namespace Discord.WebSocket
{
@@ -1248,6 +1249,42 @@ namespace Discord.WebSocket
return AddOrUpdateSticker(model);
}
///
+ /// Creates a new sticker in this guild
+ ///
+ /// The name of the sticker.
+ /// The description of the sticker.
+ /// The tags of the sticker.
+ /// The path of the file to upload.
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous creation operation. The task result contains the created sticker.
+ ///
+ public Task CreateStickerAsync(string name, string description, IEnumerable tags, string path,
+ RequestOptions options = null)
+ {
+ var fs = File.OpenRead(path);
+ return CreateStickerAsync(name, description, tags, fs, Path.GetFileName(fs.Name), options);
+ }
+ ///
+ /// Creates a new sticker in this guild
+ ///
+ /// The name of the sticker.
+ /// The description of the sticker.
+ /// The tags of the sticker.
+ /// The stream containing the file data.
+ /// The name of the file with the extension, ex: image.png
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous creation operation. The task result contains the created sticker.
+ ///
+ public async Task CreateStickerAsync(string name, string description, IEnumerable tags, Stream stream,
+ string filename, RequestOptions options = null)
+ {
+ var model = await GuildHelper.CreateStickerAsync(Discord, this, name, description, tags, stream, filename, options).ConfigureAwait(false);
+
+ return AddOrUpdateSticker(model);
+ }
+ ///
/// Deletes a sticker within this guild.
///
/// The sticker to delete.
@@ -1632,12 +1669,22 @@ namespace Discord.WebSocket
///
async Task> IGuild.GetApplicationCommandsAsync (RequestOptions options)
=> await GetApplicationCommandsAsync(options).ConfigureAwait(false);
+ ///
async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, Image image, RequestOptions options)
=> await CreateStickerAsync(name, description, tags, image, options);
+ ///
+ async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, Stream stream, string filename, RequestOptions options)
+ => await CreateStickerAsync(name, description, tags, stream, filename, options);
+ ///
+ async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, string path, RequestOptions options)
+ => await CreateStickerAsync(name, description, tags, path, options);
+ ///
async Task IGuild.GetStickerAsync(ulong id, CacheMode mode, RequestOptions options)
=> await GetStickerAsync(id, mode, options);
+ ///
async Task> IGuild.GetStickersAsync(CacheMode mode, RequestOptions options)
=> await GetStickersAsync(mode, options);
+ ///
Task IGuild.DeleteStickerAsync(ICustomSticker sticker, RequestOptions options)
=> DeleteStickerAsync(_stickers[sticker.Id], options);