Merge pull request #4 from SkyJoshua/dev

Dev
This commit is contained in:
SkyJoshua
2026-03-20 08:05:55 +00:00
committed by GitHub
4 changed files with 369 additions and 0 deletions

View 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
View 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]);
}
}
}

View 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}**");
}
}
}

View 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}`");
}
}
}