cat.
This commit is contained in:
46
SkyBot/Commands/Dev/Delete.cs
Normal file
46
SkyBot/Commands/Dev/Delete.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using SkyBot.Helpers;
|
||||||
|
using SkyBot.Models;
|
||||||
|
using Valour.Sdk.Client;
|
||||||
|
using Valour.Sdk.Models;
|
||||||
|
|
||||||
|
namespace SkyBot.Commands
|
||||||
|
{
|
||||||
|
public class Delete : ICommand
|
||||||
|
{
|
||||||
|
public string Name => "delete";
|
||||||
|
public string[] Aliases => ["del"];
|
||||||
|
public string Description => "Delete a bot message";
|
||||||
|
public string Section => "Dev";
|
||||||
|
public string Usage => "reply -> delete";
|
||||||
|
|
||||||
|
public async Task Execute(CommandContext ctx)
|
||||||
|
{
|
||||||
|
ConcurrentDictionary<long, Channel> channelCache = ctx.ChannelCache;
|
||||||
|
ValourClient client = ctx.Client;
|
||||||
|
long channelId = ctx.ChannelId;
|
||||||
|
PlanetMember member = ctx.Member;
|
||||||
|
Message message = ctx.Message;
|
||||||
|
|
||||||
|
if (channelCache.TryGetValue(channelId, out var channel))
|
||||||
|
{
|
||||||
|
if (!PermissionHelper.IsOwner(member))
|
||||||
|
{
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, "This is a Dev only command.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.ReplyToId == null)
|
||||||
|
{
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, "Please reply to a message.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client.Cache.Messages.TryGet(message.ReplyToId.Value, out var msg))
|
||||||
|
{
|
||||||
|
await msg.DeleteAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
101
SkyBot/Commands/Fun/Cat.cs
Normal file
101
SkyBot/Commands/Fun/Cat.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Text.Json;
|
||||||
|
using SkyBot.Helpers;
|
||||||
|
using SkyBot.Models;
|
||||||
|
using Valour.Sdk.Models;
|
||||||
|
using Valour.Shared.Models;
|
||||||
|
|
||||||
|
namespace SkyBot.Commands
|
||||||
|
{
|
||||||
|
public class Cat : ICommand
|
||||||
|
{
|
||||||
|
public string Name => "cat";
|
||||||
|
public string[] Aliases => ["kitty", "meow"];
|
||||||
|
public string Description => "Posts a random cat picture.";
|
||||||
|
public string Section => "Fun";
|
||||||
|
public string Usage => "cat";
|
||||||
|
|
||||||
|
private static readonly HttpClient _http = new();
|
||||||
|
|
||||||
|
public async Task Execute(CommandContext ctx)
|
||||||
|
{
|
||||||
|
ConcurrentDictionary<long, Channel> channelCache = ctx.ChannelCache;
|
||||||
|
long channelId = ctx.ChannelId;
|
||||||
|
|
||||||
|
if (!channelCache.TryGetValue(channelId, out var channel)) return;
|
||||||
|
|
||||||
|
await channel.SendIsTyping();
|
||||||
|
|
||||||
|
// Fetch a random cat from TheCatAPI
|
||||||
|
string json;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
json = await _http.GetStringAsync("https://api.thecatapi.com/v1/images/search");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, "😿 Could not fetch a cat image. Try again later.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var doc = JsonDocument.Parse(json);
|
||||||
|
var root = doc.RootElement[0];
|
||||||
|
|
||||||
|
string catUrl = root.GetProperty("url").GetString()!;
|
||||||
|
int width = root.TryGetProperty("width", out var w) ? w.GetInt32() : 0;
|
||||||
|
int height = root.TryGetProperty("height", out var h) ? h.GetInt32() : 0;
|
||||||
|
|
||||||
|
string ext = Path.GetExtension(catUrl.Split('?')[0]).ToLowerInvariant();
|
||||||
|
string mime = ext == ".png" ? "image/png"
|
||||||
|
: ext == ".gif" ? "image/gif"
|
||||||
|
: "image/jpeg";
|
||||||
|
string fileName = $"cat{ext}";
|
||||||
|
|
||||||
|
// Download the image bytes
|
||||||
|
byte[] imageBytes;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
imageBytes = await _http.GetByteArrayAsync(catUrl);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, "😿 Could not download the cat image. Try again later.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload to Valour CDN so the server can scan/serve it
|
||||||
|
string cdnUrl;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var form = new MultipartFormDataContent();
|
||||||
|
using var fileContent = new ByteArrayContent(imageBytes);
|
||||||
|
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(mime);
|
||||||
|
form.Add(fileContent, "file", fileName);
|
||||||
|
|
||||||
|
var uploadResult = await ctx.Planet.Node.PostMultipartDataWithResponse<string>("upload/image", form);
|
||||||
|
if (!uploadResult.Success)
|
||||||
|
{
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, "😿 Could not upload the cat image. Try again later.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cdnUrl = uploadResult.Data!;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, "😿 Could not upload the cat image. Try again later.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var attachment = new MessageAttachment(MessageAttachmentType.Image)
|
||||||
|
{
|
||||||
|
Location = cdnUrl,
|
||||||
|
MimeType = mime,
|
||||||
|
FileName = fileName,
|
||||||
|
Width = width,
|
||||||
|
Height = height
|
||||||
|
};
|
||||||
|
|
||||||
|
await channel.SendMessageAsync("",attachments: [attachment]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
114
SkyBot/Commands/Fun/T9Decode.cs
Normal file
114
SkyBot/Commands/Fun/T9Decode.cs
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Text;
|
||||||
|
using SkyBot.Helpers;
|
||||||
|
using SkyBot.Models;
|
||||||
|
using Valour.Sdk.Models;
|
||||||
|
|
||||||
|
namespace SkyBot.Commands
|
||||||
|
{
|
||||||
|
public class MultiTap : ICommand
|
||||||
|
{
|
||||||
|
public string Name => "t9decode";
|
||||||
|
public string[] Aliases => ["t9d"];
|
||||||
|
public string Description => "Decodes old phone keypad multi-tap input into text.";
|
||||||
|
public string Section => "Fun";
|
||||||
|
public string Usage => "multitap <digits> (e.g. 44 3 555 555 666 or reply to a message)";
|
||||||
|
|
||||||
|
private static readonly Dictionary<char, string> Keymap = new()
|
||||||
|
{
|
||||||
|
['2'] = "ABC",
|
||||||
|
['3'] = "DEF",
|
||||||
|
['4'] = "GHI",
|
||||||
|
['5'] = "JKL",
|
||||||
|
['6'] = "MNO",
|
||||||
|
['7'] = "PQRS",
|
||||||
|
['8'] = "TUV",
|
||||||
|
['9'] = "WXYZ",
|
||||||
|
};
|
||||||
|
|
||||||
|
public async Task Execute(CommandContext ctx)
|
||||||
|
{
|
||||||
|
ConcurrentDictionary<long, Channel> channelCache = ctx.ChannelCache;
|
||||||
|
long channelId = ctx.ChannelId;
|
||||||
|
Message message = ctx.Message;
|
||||||
|
string[] args = ctx.Args;
|
||||||
|
|
||||||
|
if (!channelCache.TryGetValue(channelId, out var channel)) return;
|
||||||
|
|
||||||
|
string raw;
|
||||||
|
|
||||||
|
if (message.ReplyToId.HasValue)
|
||||||
|
{
|
||||||
|
var replyMessage = await message.FetchReplyMessageAsync();
|
||||||
|
raw = replyMessage?.Content ?? "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (args.Length == 0)
|
||||||
|
{
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, "Please provide digits to decode, or reply to a message. Example: `multitap 44 3 555 555 666`");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
raw = string.Join("", args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip anything that isn't a digit
|
||||||
|
string input = new([..raw.Where(char.IsDigit)]);
|
||||||
|
|
||||||
|
var result = new StringBuilder();
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (i < input.Length)
|
||||||
|
{
|
||||||
|
char digit = input[i];
|
||||||
|
|
||||||
|
if (digit == '0')
|
||||||
|
{
|
||||||
|
result.Append(' ');
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 = silent same-key separator if surrounded by the same digit, otherwise a space
|
||||||
|
if (digit == '1')
|
||||||
|
{
|
||||||
|
int j = i;
|
||||||
|
while (j < input.Length && input[j] == '1') j++;
|
||||||
|
|
||||||
|
char before = i > 0 ? input[i - 1] : '\0';
|
||||||
|
char after = j < input.Length ? input[j] : '\0';
|
||||||
|
bool sameKey = before >= '2' && before <= '9' && before == after;
|
||||||
|
|
||||||
|
if (!sameKey) result.Append(' ');
|
||||||
|
i = j;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Keymap.TryGetValue(digit, out string? letters))
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count consecutive presses of the same digit
|
||||||
|
int count = 0;
|
||||||
|
while (i + count < input.Length && input[i + count] == digit)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
int letterIndex = (count - 1) % letters.Length;
|
||||||
|
result.Append(letters[letterIndex]);
|
||||||
|
i += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
string decoded = result.ToString().Trim();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(decoded))
|
||||||
|
{
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, "Couldn't decode anything from that input.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, $"📱 **{decoded}**");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
108
SkyBot/Commands/Fun/T9Encode.cs
Normal file
108
SkyBot/Commands/Fun/T9Encode.cs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Text;
|
||||||
|
using SkyBot.Helpers;
|
||||||
|
using SkyBot.Models;
|
||||||
|
using Valour.Sdk.Models;
|
||||||
|
|
||||||
|
namespace SkyBot.Commands
|
||||||
|
{
|
||||||
|
public class T9Encode : ICommand
|
||||||
|
{
|
||||||
|
public string Name => "t9encode";
|
||||||
|
public string[] Aliases => ["t9e"];
|
||||||
|
public string Description => "Encodes text into old phone keypad multi-tap digits.";
|
||||||
|
public string Section => "Fun";
|
||||||
|
public string Usage => "t9encode <text> (or reply to a message)";
|
||||||
|
|
||||||
|
// Maps each letter to (key digit, press count)
|
||||||
|
private static readonly Dictionary<char, (char Key, int Presses)> Charmap = BuildCharmap();
|
||||||
|
|
||||||
|
private static Dictionary<char, (char Key, int Presses)> BuildCharmap()
|
||||||
|
{
|
||||||
|
Dictionary<char, string> keymap = new()
|
||||||
|
{
|
||||||
|
['2'] = "ABC",
|
||||||
|
['3'] = "DEF",
|
||||||
|
['4'] = "GHI",
|
||||||
|
['5'] = "JKL",
|
||||||
|
['6'] = "MNO",
|
||||||
|
['7'] = "PQRS",
|
||||||
|
['8'] = "TUV",
|
||||||
|
['9'] = "WXYZ",
|
||||||
|
};
|
||||||
|
|
||||||
|
var map = new Dictionary<char, (char, int)>();
|
||||||
|
foreach (var (key, letters) in keymap)
|
||||||
|
for (int i = 0; i < letters.Length; i++)
|
||||||
|
map[letters[i]] = (key, i + 1);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Execute(CommandContext ctx)
|
||||||
|
{
|
||||||
|
ConcurrentDictionary<long, Channel> channelCache = ctx.ChannelCache;
|
||||||
|
long channelId = ctx.ChannelId;
|
||||||
|
Message message = ctx.Message;
|
||||||
|
string[] args = ctx.Args;
|
||||||
|
|
||||||
|
if (!channelCache.TryGetValue(channelId, out var channel)) return;
|
||||||
|
|
||||||
|
string raw;
|
||||||
|
|
||||||
|
if (message.ReplyToId.HasValue)
|
||||||
|
{
|
||||||
|
var replyMessage = await message.FetchReplyMessageAsync();
|
||||||
|
raw = replyMessage?.Content ?? "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (args.Length == 0)
|
||||||
|
{
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, "Please provide text to encode, or reply to a message.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
raw = string.Join(" ", args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(raw))
|
||||||
|
{
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, "No text to encode.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new StringBuilder();
|
||||||
|
char prevKey = '\0';
|
||||||
|
|
||||||
|
foreach (char c in raw.ToUpper())
|
||||||
|
{
|
||||||
|
if (c == ' ')
|
||||||
|
{
|
||||||
|
result.Append('0');
|
||||||
|
prevKey = '\0';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Charmap.TryGetValue(c, out var entry))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If this letter uses the same key as the previous one, insert a 1 separator
|
||||||
|
if (entry.Key == prevKey)
|
||||||
|
result.Append('1');
|
||||||
|
|
||||||
|
result.Append(entry.Key, entry.Presses);
|
||||||
|
prevKey = entry.Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
string encoded = result.ToString().Trim('0');
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(encoded))
|
||||||
|
{
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, "Couldn't encode anything from that input.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await MessageHelper.ReplyAsync(ctx, channel, $"📱 `{encoded}`");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user