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 => [];
|
||||
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