Compare commits

..

No commits in common. "347297fb120aad0bb7fce35250884dc340a7b889" and "d58c5166490cefdad4a317abb3f8c18dc7e2de19" have entirely different histories.

41 changed files with 14818 additions and 14969 deletions

View file

@ -2,23 +2,6 @@
Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
## [5.1.3] - 08.07.2024
### Added
- Added `'quran` command, which will show the provided ayah in english and arabic, including recitation by Alafasy
### Changed
- Replying to the bot's message in the channel where chatterbot is enabled will also trigger the ai response, as if you pinged the bot. This only works for chatterbot, but not for ellie ai command prompts
### Fixed
- Fixed `'stickeradd` it now properly supports 300x300 image uploads.
- Bot should now trim the invalid characters from chatterbot usernames to avoid openai errors
- Fixed prompt triggering chatterbot responses twice
- Honeypot commands now actually works
## [5.1.2] - 29.06.2024
### Fixed

View file

@ -1,7 +1,7 @@
namespace EllieBot.Marmalade;
/// <summary>
/// Marks the class as a service which can be used within the same Marmalade
/// Marks the class as a service which can be used within the same Medusa
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class svcAttribute : Attribute

View file

@ -110,7 +110,7 @@ public sealed class Bot : IBot
var svcs = new Container();
// this is required in order for marmalade unloading to work
// this is required in order for medusa unloading to work
// svcs.Components.Remove<IPlanner, Planner>();
// svcs.Components.Add<IPlanner, RemovablePlanner>();

View file

@ -4,7 +4,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<Version>5.1.3</Version>
<Version>5.1.2</Version>
<!-- Output/build -->
<RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>

View file

@ -5,7 +5,7 @@ using EllieBot.Db.Models;
using System.Threading.Channels;
namespace EllieBot.Modules.Administration.Honeypot;
/*
public sealed class HoneyPotService : IHoneyPotService, IReadyExecutor, IExecNoCommand, IEService
{
private readonly DbService _db;
@ -93,3 +93,4 @@ public sealed class HoneyPotService : IHoneyPotService, IReadyExecutor, IExecNoC
}
}
}
*/

View file

@ -1,7 +1,7 @@
using EllieBot.Modules.Administration.Honeypot;
namespace EllieBot.Modules.Administration;
/*
public partial class Administration
{
[Group]
@ -27,3 +27,4 @@ public partial class Administration
}
}
}
*/

View file

@ -1,6 +1,7 @@
namespace EllieBot.Modules.Administration.Honeypot;
/*
public interface IHoneyPotService
{
public Task<bool> ToggleHoneypotChannel(ulong guildId, ulong channelId);
}
*/

View file

@ -3,7 +3,7 @@
namespace EllieBot.Modules.Administration;
public sealed class DummyLogCommandService : ILogCommandService
#if GLOBAL_ELLIE
#if GLOBAL_NADEKO
, IEService
#endif
{

View file

@ -8,8 +8,8 @@ using EllieBot.Db.Models;
namespace EllieBot.Modules.Administration;
public sealed class LogCommandService : ILogCommandService, IReadyExecutor
#if !GLOBAL_ELLIE
, IEService // don't load this service on global ellie
#if !GLOBAL_NADEKO
, IEService // don't load this service on global nadeko
#endif
{
public ConcurrentDictionary<ulong, LogSetting> GuildLogSettings { get; }

View file

@ -228,7 +228,7 @@ public class UserPunishService : IEService, IReadyExecutor
case PunishmentAction.RemoveRoles:
return botUser.GuildPermissions.ManageRoles;
case PunishmentAction.ChatMute:
return botUser.GuildPermissions.ManageRoles; // adds ellie-mute role
return botUser.GuildPermissions.ManageRoles; // adds nadeko-mute role
case PunishmentAction.VoiceMute:
return botUser.GuildPermissions.MuteMembers;
case PunishmentAction.AddRole:

View file

@ -88,16 +88,14 @@ public class ChatterBotService : IExecOnMessage
public string PrepareMessage(IUserMessage msg)
{
var ellieId = _client.CurrentUser.Id;
var normalMention = $"<@{ellieId}> ";
var nickMention = $"<@!{ellieId}> ";
var nadekoId = _client.CurrentUser.Id;
var normalMention = $"<@{nadekoId}> ";
var nickMention = $"<@!{nadekoId}> ";
string message;
if (msg.Content.StartsWith(normalMention, StringComparison.InvariantCulture))
message = msg.Content[normalMention.Length..].Trim();
else if (msg.Content.StartsWith(nickMention, StringComparison.InvariantCulture))
message = msg.Content[nickMention.Length..].Trim();
else if (msg.ReferencedMessage?.Author.Id == ellieId)
message = msg.Content;
else
return null;

View file

@ -3,12 +3,10 @@ using Newtonsoft.Json;
using OneOf.Types;
using System.Net.Http.Json;
using SharpToken;
using System.CodeDom;
using System.Text.RegularExpressions;
namespace EllieBot.Modules.Games.Common.ChatterBot;
public partial class OfficialGptSession : IChatterBotSession
public class OfficialGptSession : IChatterBotSession
{
private string Uri
=> $"https://api.openai.com/v1/chat/completions";
@ -18,7 +16,7 @@ public partial class OfficialGptSession : IChatterBotSession
private readonly int _maxHistory;
private readonly int _maxTokens;
private readonly int _minTokens;
private readonly string _ellieUsername;
private readonly string _nadekoUsername;
private readonly GptEncoding _encoding;
private List<GPTMessage> messages = new();
private readonly IHttpClientFactory _httpFactory;
@ -31,7 +29,7 @@ public partial class OfficialGptSession : IChatterBotSession
int maxTokens,
int minTokens,
string personality,
string ellieUsername,
string nadekoUsername,
IHttpClientFactory factory)
{
_apiKey = apiKey;
@ -47,31 +45,24 @@ public partial class OfficialGptSession : IChatterBotSession
_maxHistory = chatHistory;
_maxTokens = maxTokens;
_minTokens = minTokens;
_ellieUsername = UsernameCleaner().Replace(ellieUsername, "");
_nadekoUsername = nadekoUsername;
_encoding = GptEncoding.GetEncodingForModel(_model);
messages.Add(new()
{
Role = "system",
Content = personality,
Name = _ellieUsername
Name = _nadekoUsername
});
}
[GeneratedRegex("[^a-zA-Z0-9_-]")]
private static partial Regex UsernameCleaner();
public async Task<OneOf.OneOf<ThinkResult, Error<string>>> Think(string input, string username)
{
username = UsernameCleaner().Replace(username, "");
messages.Add(new()
{
Role = "user",
Content = input,
Name = username
});
while (messages.Count > _maxHistory + 2)
{
messages.RemoveAt(1);
@ -126,7 +117,7 @@ public partial class OfficialGptSession : IChatterBotSession
{
Role = "assistant",
Content = message,
Name = _ellieUsername
Name = _nadekoUsername
});
return new ThinkResult()

View file

@ -9,8 +9,8 @@ namespace EllieBot.Modules.Help;
public sealed partial class Help : EllieModule<HelpService>
{
public const string PATREON_URL = "https://patreon.com/elliebot";
public const string PAYPAL_URL = "https://paypal.me/toastiet0ast";
public const string PATREON_URL = "https://patreon.com/toastie_t0ast";
public const string PAYPAL_URL = "https://paypal.me/EmotionChild";
private readonly ICommandsUtilityService _cus;
private readonly CommandService _cmds;
@ -529,7 +529,7 @@ public sealed partial class Help : EllieModule<HelpService>
*Keep in mind that running the bot on your computer means that the bot will be offline when you turn off your computer*
- You can find the selfhosting guides by using the `.guide` command and clicking on the second link that pops up.
- If you decide to selfhost the bot, still consider [supporting the project](https://patreon.com/join/elliebot) to keep the development going :)
- If you decide to selfhost the bot, still consider [supporting the project](https://patreon.com/join/toastie_t0ast) to keep the development going :)
""",
true);
@ -551,7 +551,7 @@ public sealed partial class Help : EllieModule<HelpService>
eb
.WithDescription("""
EllieBot relies on donations to keep the servers, services and APIs running.
Donating will give you access to some exclusive features. You can read about them on the [patreon page](https://patreon.com/join/elliebot)
Donating will give you access to some exclusive features. You can read about them on the [patreon page](https://patreon.com/join/toastie_t0ast)
""")
.AddField("Donation Instructions",
$"""
@ -559,7 +559,7 @@ public sealed partial class Help : EllieModule<HelpService>
**Step 1:** Pledge on Patreon
`1.` Go to <https://patreon.com/join/elliebot> and choose a tier.
`1.` Go to <https://patreon.com/join/toastie_t0ast> and choose a tier.
`2.` Make sure your payment is processed and accepted.
**Step 2** 🤝 Connect your Discord account 🤝

View file

@ -130,7 +130,7 @@ public class CryptoService : IEService
await _getCryptoLock.WaitAsync();
try
{
var data = await _cache.GetOrAddAsync(new("ellie:crypto_data"),
var data = await _cache.GetOrAddAsync(new("nadeko:crypto_data"),
async () =>
{
try

View file

@ -1,102 +0,0 @@
using EllieBot.Modules.Searches.Common;
using System.Net.Http.Json;
using System.Text.Json.Serialization;
namespace EllieBot.Modules.Searches;
public partial class Searches
{
public partial class ReligiousCommands : EllieModule
{
private readonly IHttpClientFactory _httpFactory;
public ReligiousCommands(IHttpClientFactory httpFactory)
{
_httpFactory = httpFactory;
}
[Cmd]
[RequireContext(ContextType.Guild)]
public async Task Bible(string book, string chapterAndVerse)
{
var obj = new BibleVerses();
try
{
using var http = _httpFactory.CreateClient();
obj = await http.GetFromJsonAsync<BibleVerses>($"https://bible-api.com/{book} {chapterAndVerse}");
}
catch
{
}
if (obj.Error is not null || obj.Verses is null || obj.Verses.Length == 0)
await Response().Error(obj.Error ?? "No verse found.").SendAsync();
else
{
var v = obj.Verses[0];
await Response()
.Embed(_sender.CreateEmbed()
.WithOkColor()
.WithTitle($"{v.BookName} {v.Chapter}:{v.Verse}")
.WithDescription(v.Text))
.SendAsync();
}
}
[Cmd]
[RequireContext(ContextType.Guild)]
public async Task Quran(string ayah)
{
using var http = _httpFactory.CreateClient();
var obj = await http.GetFromJsonAsync<QuranResponse<QuranAyah>>($"https://api.alquran.cloud/v1/ayah/{Uri.EscapeDataString(ayah)}/editions/en.asad,ar.alafasy");
if(obj is null or not { Code: 200 })
{
await Response().Error("No verse found.").SendAsync();
return;
}
var english = obj.Data[0];
var arabic = obj.Data[1];
await using var audio = await http.GetStreamAsync(arabic.Audio);
await Response()
.Embed(_sender.CreateEmbed()
.WithOkColor()
.AddField("Arabic", arabic.Text)
.AddField("English", english.Text)
.WithFooter(arabic.Number.ToString()))
.File(audio, Uri.EscapeDataString(ayah) + ".mp3")
.SendAsync();
}
}
}
public sealed class QuranResponse<T>
{
[JsonPropertyName("code")]
public int Code { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("data")]
public T[] Data { get; set; }
}
public sealed class QuranAyah
{
[JsonPropertyName("number")]
public int Number { get; set; }
[JsonPropertyName("audio")]
public string Audio { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("text")]
public string Text { get; set; }
}

View file

@ -528,6 +528,34 @@ public partial class Searches : EllieModule<SearchesService>
}
}
[Cmd]
[RequireContext(ContextType.Guild)]
public async Task Bible(string book, string chapterAndVerse)
{
var obj = new BibleVerses();
try
{
using var http = _httpFactory.CreateClient();
obj = await http.GetFromJsonAsync<BibleVerses>($"https://bible-api.com/{book} {chapterAndVerse}");
}
catch
{
}
if (obj.Error is not null || obj.Verses is null || obj.Verses.Length == 0)
await Response().Error(obj.Error ?? "No verse found.").SendAsync();
else
{
var v = obj.Verses[0];
await Response()
.Embed(_sender.CreateEmbed()
.WithOkColor()
.WithTitle($"{v.BookName} {v.Chapter}:{v.Verse}")
.WithDescription(v.Text))
.SendAsync();
}
}
[Cmd]
public async Task Steam([Leftover] string query)
{

View file

@ -126,7 +126,7 @@ public class SearchesService : IEService
{
query = query.Trim().ToLowerInvariant();
return await _c.GetOrAddAsync(new($"ellie_weather_{query}"),
return await _c.GetOrAddAsync(new($"nadeko_weather_{query}"),
async () => await GetWeatherDataFactory(query),
TimeSpan.FromHours(3));
}
@ -156,7 +156,7 @@ public class SearchesService : IEService
public Task<((string Address, DateTime Time, string TimeZoneName), TimeErrors?)> GetTimeDataAsync(string arg)
=> GetTimeDataFactory(arg);
//return _cache.GetOrAddCachedDataAsync($"ellie_time_{arg}",
//return _cache.GetOrAddCachedDataAsync($"nadeko_time_{arg}",
// GetTimeDataFactory,
// arg,
// TimeSpan.FromMinutes(1));

View file

@ -196,14 +196,14 @@ public sealed class AiAssistantService
if (guild is not SocketGuild sg)
return false;
var ellieId = _client.CurrentUser.Id;
var nadekoId = _client.CurrentUser.Id;
var channel = msg.Channel as ITextChannel;
if (channel is null)
return false;
var normalMention = $"<@{ellieId}> ";
var nickMention = $"<@!{ellieId}> ";
var normalMention = $"<@{nadekoId}> ";
var nickMention = $"<@!{nadekoId}> ";
string query;
if (msg.Content.StartsWith(normalMention, StringComparison.InvariantCulture))
query = msg.Content[normalMention.Length..].Trim();
@ -251,7 +251,7 @@ public sealed class AiAssistantService
return false;
await _cbs.RunChatterBot(sg, msg, channel, sess, query);
return true;
return false;
}
var commandString = GetCommandString(model);
@ -293,7 +293,7 @@ public sealed class AiAssistantService
GetCommandErrorResult.RateLimitHit
=> "You've spent your daily requests quota.",
GetCommandErrorResult.NotAuthorized
=> "In order to use this command you have to have a 5$ or higher subscription at <https://patreon.com/elliebot>",
=> "In order to use this command you have to have a 5$ or higher subscription at <https://patreon.com/nadekobot>",
GetCommandErrorResult.Unknown
=> "The service is temporarily unavailable.",
_ => throw new ArgumentOutOfRangeException()

View file

@ -8,7 +8,7 @@ public partial class Utility
private readonly IEnumerable<IConfigService> _settingServices;
public ConfigCommands(IEnumerable<IConfigService> settingServices)
=> _settingServices = settingServices.Where(x => x.Name != "marmalade");
=> _settingServices = settingServices.Where(x => x.Name != "medusa");
[Cmd]
[OwnerOnly]

View file

@ -459,10 +459,8 @@ public partial class Utility : EllieModule
public async Task StickerAdd(string name = null, string description = null, params string[] tags)
{
string format;
Stream stream = null;
Stream stream;
try
{
if (ctx.Message.Stickers.Count is 1 && ctx.Message.Stickers.First() is SocketSticker ss)
{
name ??= ss.Name;
@ -473,40 +471,6 @@ public partial class Utility : EllieModule
using var http = _httpFactory.CreateClient();
stream = await http.GetStreamAsync(ss.GetStickerUrl());
}
else if (ctx.Message.Attachments.Count is 1 && name is not null)
{
if (tags.Length == 0)
tags = [name];
if (ctx.Message.Attachments.Count != 1)
{
await Response().Error(strs.sticker_error).SendAsync();
return;
}
var attach = ctx.Message.Attachments.First();
if (attach.Size > 512_000 || attach.Width != 300 || attach.Height != 300)
{
await Response().Error(strs.sticker_error).SendAsync();
return;
}
format = attach.Filename
.Split('.')
.Last()
.ToLowerInvariant();
if (string.IsNullOrWhiteSpace(format) || (format != "png" && format != "apng"))
{
await Response().Error(strs.sticker_error).SendAsync();
return;
}
using var http = _httpFactory.CreateClient();
stream = await http.GetStreamAsync(attach.Url);
}
else
{
await Response().Error(strs.sticker_error).SendAsync();
@ -515,6 +479,9 @@ public partial class Utility : EllieModule
try
{
if (tags.Length == 0)
tags = [name];
await ctx.Guild.CreateStickerAsync(
name,
stream,
@ -525,16 +492,14 @@ public partial class Utility : EllieModule
await ctx.OkAsync();
}
catch
(Exception ex)
catch (Exception ex)
{
Log.Warning(ex, "Error occurred while adding a sticker: {Message}", ex.Message);
await Response().Error(strs.error_occured).SendAsync();
}
}
finally
{
await (stream?.DisposeAsync() ?? ValueTask.CompletedTask);
await stream.DisposeAsync();
}
}

View file

@ -34,7 +34,7 @@ public sealed class Creds : IBotCredentials
Go to https://dashy.elliebot.net/me and login with your discord account
Go to the Keys page and click "Generate New Key" and copy it here
You and anyone else with the permission to run `.prompt` command will be able to use natural language to run bot's commands.
For example '@Bot how's the weather in Paris' will return the current weather in Paris as if you were to run `.weather Paris` command.
For example '@Bot how's the weather in Paris' will return the current weather in Paris as if you were to run `.weather Paris` command
""")]
public string EllieAiToken { get; set; }

View file

@ -11,5 +11,5 @@ public abstract class DbService
public abstract Task SetupAsync();
public abstract DbContext CreateRawDbContext(string dbType, string connString);
public abstract EllieContext GetDbContext();
public abstract DbContext GetDbContext();
}

View file

@ -29,8 +29,7 @@ public class EllieInteractionService : IEllieInteractionService, IEService
Func<SocketMessageComponent, T, Task> onTrigger,
in T state,
bool singleUse = true,
bool clearAfter = true
)
bool clearAfter = true)
=> Create(userId,
button,
((Func<T, Func<SocketMessageComponent, Task>>)((data)

View file

@ -10,7 +10,7 @@ public sealed class EllieButtonInteractionHandler : EllieInteractionBase
bool onlyAuthor,
bool singleUse = true,
bool clearAfter = true)
: base(client, authorId, button.CustomId, onAction, onlyAuthor, singleUse, clearAfter)
: base(client, authorId, button.CustomId, onAction, onlyAuthor, singleUse)
{
Button = button;
}

View file

@ -19,11 +19,11 @@ public class FilterAdapter : PreconditionAttribute
CommandInfo command,
IServiceProvider services)
{
var marmaladeContext = ContextAdapterFactory.CreateNew(context,
var medusaContext = ContextAdapterFactory.CreateNew(context,
_strings,
services);
var result = await _filterAttribute.CheckAsync(marmaladeContext);
var result = await _filterAttribute.CheckAsync(medusaContext);
if (!result)
return PreconditionResult.FromError($"Precondition '{_filterAttribute.GetType().Name}' failed.");

View file

@ -1,4 +1,4 @@
# DO NOT CHANGE
# DO NOT CHANGE
version: 7
# Bot token. Do not share with anyone ever -> https://discordapp.com/developers/applications/
token: ""
@ -18,7 +18,6 @@ totalShards: 1
# Go to the Keys page and click "Generate New Key" and copy it here
# You and anyone else with the permission to run `.prompt` command will be able to use natural language to run bot's commands.
# For example '@Bot how's the weather in Paris' will return the current weather in Paris as if you were to run `.weather Paris` command.
# ⚠ This does not currently work and is a work in progress.
ellieAiToken:
# Login to https://console.cloud.google.com, create a new project, go to APIs & Services -> Library -> YouTube Data API and enable it.
# Then, go to APIs and Services -> Credentials and click Create credentials -> API key.

View file

@ -1192,8 +1192,6 @@ xpreset:
- xpreset
bible:
- bible
quran:
- quran
edit:
- edit
delete:

View file

@ -64,7 +64,7 @@ greetmsg:
desc: |-
Sets a new join announcement message which will be shown in the current channel.
Write `%user.mention%` if you want to mention the new member.
Full list of placeholders can be found here <https://docs.elliebot.net/ellie/features/placeholders/>
Full list of placeholders can be found here <https://docs.elliebot.net/ellie/placeholders/>
Using this command with no message will show the current greet message.
You can use embed json from <https://eb.elliebot.net/> instead of regular text, if you want the message to be embedded.
ex:
@ -82,7 +82,7 @@ byemsg:
desc: |-
Sets a new leave announcement message which will be shown in the current channel.
Type `%user.name%` to show the name of the user who left.
Full list of placeholders can be found here <https://docs.elliebot.net/ellie/features/placeholders/>
Full list of placeholders can be found here <https://docs.elliebot.net/ellie/placeholders/>
Using this command with no message will show the current bye message.
You can use embed json from <https://eb.elliebot.net/> instead of regular text, if you want the message to be embedded.
ex:
@ -138,7 +138,7 @@ boostmsg:
desc: |-
Sets a new boost announcement message which will be shown in the current channel.
Type `%user.mention%` if you want to mention the booster.
Full list of placeholders can be found here <https://docs.elliebot.net/ellie/features/placeholders/>
Full list of placeholders can be found here <https://docs.elliebot.net/ellie/placeholders/>
Using this command with no message will show the current boost message.
You can use embed json from <https://eb.elliebot.net/> instead of regular text, if you want the message to be embedded.
ex:
@ -378,7 +378,7 @@ iamnot:
- role:
desc: "The role to remove."
expradd:
desc: 'Add an expression with a trigger and a response. Bot will post a response whenever someone types the trigger word. Running this command in a server requires the Administrator permission. Running this command in DM is Bot Owner only and adds a new global expression. Guide [here](<https://docs.elliebot.net/ellie/features/expressions/>)'
desc: 'Add an expression with a trigger and a response. Bot will post a response whenever someone types the trigger word. Running this command in a server requires the Administrator permission. Running this command in DM is Bot Owner only and adds a new global expression. Guide [here](<https://docs.elliebot.net/ellie/expressions/>)'
ex:
- '"hello" Hi there %user.mention%'
params:
@ -387,7 +387,7 @@ expradd:
response:
desc: "The text of the message that shows up when a user types the trigger word."
expraddserver:
desc: 'Add an expression with a trigger and a response in this server. Bot will post a response whenever someone types the trigger word. This command is useful if you want to lower the permission requirement for managing expressions by using `{0}dpo`. Guide [here](<https://docs.elliebot.net/ellie/features/expressions/>).'
desc: 'Add an expression with a trigger and a response in this server. Bot will post a response whenever someone types the trigger word. This command is useful if you want to lower the permission requirement for managing expressions by using `{0}dpo`. Guide [here](<https://docs.elliebot.net/ellie/expressions/>).'
ex:
- '"hello" Hi there %user.mention%'
params:
@ -2180,7 +2180,7 @@ delallquotes:
- keyword:
desc: "The keyword to search for in the text."
greetdmmsg:
desc: Sets a new join announcement message which will be sent to the user who joined. Type `%user.mention%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <https://eb.elliebot.net> instead of a regular text, if you want the message to be embedded.
desc: Sets a new join announcement message which will be sent to the user who joined. Type `%user.mention%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <https://eb.elliebot.net/> instead of a regular text, if you want the message to be embedded.
ex:
- Welcome to the server, %user.mention%
params:
@ -2289,11 +2289,7 @@ emojiremove:
- emotes:
desc: "The list of emojis to be removed from the server."
stickeradd:
desc: |-
Adds the sticker from your message to this server.
Send the sticker along with this command (in the same message).
Alternatively you can upload an image along with this command but you have to specify the name.
The image must be 300x300 in .png or .apng format and up to 512KB in size.
desc: Adds the sticker from your message to this server. Send the sticker along with this command (in the same message).
ex:
- ''
- name "description" tag1 tag2 tagN
@ -4080,16 +4076,6 @@ bible:
desc: "The name of the biblical book being referenced."
chapterAndVerse:
desc: "The reference to a specific passage in the Bible, such as 'Genesis 3:15'"
quran:
desc: |-
Shows the text of an ayah of the Quran, as well as the recitation by Alafasy.
Supply surah:ayah, or ayah number. For instance, 262 or 2:255 will both get you Ayat Al Kursi
ex:
- 2:255
- 262
params:
- ayah:
desc: "The number of the ayah in the Quran, for example 2:255."
edit:
desc: Edits bot's message, you have to specify message ID and new text. You can optionally specify target channel. Supports embeds.
ex:
@ -4214,7 +4200,7 @@ marmaladeunload:
desc: "The name of a specific marmalade to be unloaded."
marmaladeinfo:
desc: |-
Shows information about the specified marmalade such as the author, name, description, list of canaries, number of commands etc.
Shows information about the specified marmalade such as the author, name, description, list of sneks, number of commands etc.
Provide no name to see the basic information about all loaded marmalades.
Read about the marmalade system [here](https://docs.elliebot.net/ellie/marmalade/creating-a-marmalade/)
ex:

View file

@ -1067,7 +1067,8 @@
"xpshop_already_owned": "You already own this item.",
"xpshop_item_not_found": "An item with that key doesn't exist.",
"xpshop_website": "You can see the list of all Xp Shop items here: <https://beta.elliebot.net>",
"sticker_error": "You must either send a sticker along with this command, or upload a 300x300 .png or .apng image. Up to 512KB in size.",
"sticker_invalid_size": "Stickers must be exactly 300x300 pixels.",
"sticker_error": "You must either send a sticker along with this command, or upload a 300x300 .png or .apng image.",
"sticker_missing_name": "Please specify a name for the sticker.",
"thread_deleted": "Thread Deleted",
"thread_created": "Thread Created",