Skip to content

Instantly share code, notes, and snippets.

@Sighyu
Created March 3, 2026 06:35
Show Gist options
  • Select an option

  • Save Sighyu/939369b55c405db87135d46c1dcfb65d to your computer and use it in GitHub Desktop.

Select an option

Save Sighyu/939369b55c405db87135d46c1dcfb65d to your computer and use it in GitHub Desktop.
MakeItAQuoteAPI
[Command("quote")]
[Description("Generate a Make it a Quote image for the supplied snowflake.")]
[InteractionInstallType(DiscordApplicationIntegrationType.UserInstall, DiscordApplicationIntegrationType.GuildInstall)]
[InteractionAllowedContexts(DiscordInteractionContextType.Guild, DiscordInteractionContextType.BotDM, DiscordInteractionContextType.PrivateChannel)]
public static async ValueTask QuoteAsync(
SlashCommandContext ctx,
[Parameter("user_id"), Description("Target user snowflake (ID)")] string userId,
[Parameter("text"), Description("Text for the quote")] string text,
[Parameter("color"), Description("Use colored background")] bool? color = null,
[Parameter("beta"), Description("Use the beta renderer")] bool? beta = null)
{
bool shouldEphemeral = ctx.Guild is not null;
if (!CommandConfig.IsUserAllowed(ctx.User.Id))
{
await ctx.RespondAsync("You are not authorized to use this command.\n https://gif.fxtwitter.com/tweet_video/G7FujbCbQAAsUIi.gif", shouldEphemeral);
return;
}
if (!TryParseSnowflake(userId, out var snowflake))
{
await ctx.RespondAsync("Invalid user supplied. Mention them or paste the numeric ID.", shouldEphemeral);
return;
}
await ctx.DeferResponseAsync();
try
{
var user = await ctx.Client.GetUserAsync(snowflake);
var avatar = user.GetAvatarUrl(MediaFormat.Png) ?? user.DefaultAvatarUrl;
var username = user.Username;
var displayName = user.GlobalName;
var useColor = color ?? false;
var useBeta = beta ?? false;
var quote = new MiQ()
.SetText(text)
.SetAvatar(avatar)
.SetUsername(username)
.SetDisplayName(displayName)
.SetColor(useColor)
.SetWatermark(QuoteConstants.DefaultWatermark);
var buffer = await quote.GenerateRawAsync(useBeta);
await using var imageStream = new MemoryStream(buffer);
var responseBuilder = new DiscordMessageBuilder()
.WithContent($"Quote for <@{snowflake}> ({snowflake})")
.AddFile("quote.png", imageStream);
await ctx.EditResponseAsync(responseBuilder);
}
catch (Exception ex)
{
await ctx.EditResponseAsync(new DiscordMessageBuilder()
.WithContent($"Failed to generate quote: {ex.Message}"));
}
}
using System.Net.Http.Json;
using System.Text.Json;
namespace MakeItAQuoteBot;
internal sealed class MiQ
{
private static readonly HttpClient Http = new()
{
Timeout = TimeSpan.FromSeconds(30)
};
public QuoteFormat Format { get; } = new();
public MiQ SetText(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
throw new ArgumentException("Text is required.", nameof(text));
}
Format.Text = text;
return this;
}
public MiQ SetAvatar(string? avatar)
{
Format.Avatar = avatar;
return this;
}
public MiQ SetUsername(string username)
{
Format.Username = username;
return this;
}
public MiQ SetDisplayName(string displayName)
{
Format.DisplayName = displayName;
return this;
}
public MiQ SetColor(bool color)
{
Format.Color = color;
return this;
}
public MiQ SetWatermark(string watermark)
{
if (string.IsNullOrWhiteSpace(watermark))
{
throw new ArgumentException("Watermark must be provided.", nameof(watermark));
}
Format.Watermark = watermark;
return this;
}
public async Task<string> GenerateUrlAsync(CancellationToken cancellationToken = default)
{
EnsureText();
try
{
using var response = await Http.PostAsJsonAsync(QuoteConstants.ApiUrl, Format, cancellationToken);
await EnsureSuccess(response);
var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
using var document = await JsonDocument.ParseAsync(stream, cancellationToken: cancellationToken);
if (!document.RootElement.TryGetProperty("url", out var urlElement))
{
throw new InvalidOperationException("API response did not include a url property.");
}
var url = urlElement.GetString();
if (string.IsNullOrWhiteSpace(url))
{
throw new InvalidOperationException("API response contained an empty url.");
}
return url;
}
catch (Exception ex) when (ex is not InvalidOperationException)
{
throw new InvalidOperationException($"Failed to generate quote URL: {ex.Message}", ex);
}
}
public async Task<byte[]> GenerateRawAsync(bool useBeta = false, CancellationToken cancellationToken = default)
{
EnsureText();
try
{
if (useBeta)
{
using var betaResponse = await Http.PostAsJsonAsync(QuoteConstants.BetaApiUrl, Format, cancellationToken);
await EnsureSuccess(betaResponse);
return await betaResponse.Content.ReadAsByteArrayAsync(cancellationToken);
}
var url = await GenerateUrlAsync(cancellationToken);
using var imageResponse = await Http.GetAsync(url, cancellationToken);
await EnsureSuccess(imageResponse);
return await imageResponse.Content.ReadAsByteArrayAsync(cancellationToken);
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to generate quote image: {ex.Message}", ex);
}
}
private static async Task EnsureSuccess(HttpResponseMessage response)
{
if (response.IsSuccessStatusCode)
{
return;
}
var body = await response.Content.ReadAsStringAsync();
throw new HttpRequestException($"Status {(int)response.StatusCode}: {body}");
}
private void EnsureText()
{
if (string.IsNullOrWhiteSpace(Format.Text))
{
throw new InvalidOperationException("Text is required before generating a quote.");
}
}
}
namespace MakeItAQuoteBot;
internal static class QuoteConstants
{
public const string ApiUrl = "https://api.voids.top/fakequote";
public const string BetaApiUrl = "https://api.voids.top/fakequotebeta";
public const string DefaultWatermark = "Make it a Quote#6666";
}
using System.Text.Json.Serialization;
namespace MakeItAQuoteBot;
internal sealed class QuoteFormat
{
[JsonPropertyName("text")]
public string Text { get; set; } = string.Empty;
[JsonPropertyName("avatar")]
public string? Avatar { get; set; }
[JsonPropertyName("username")]
public string Username { get; set; } = string.Empty;
[JsonPropertyName("display_name")]
public string DisplayName { get; set; } = string.Empty;
[JsonPropertyName("color")]
public bool Color { get; set; }
[JsonPropertyName("watermark")]
public string Watermark { get; set; } = QuoteConstants.DefaultWatermark;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment