mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3fc53b0609 | ||
|
62ec2241e4 | ||
|
75f8254a8e | ||
|
f23ffe0c67 | ||
|
d1a818542c | ||
|
15f67e3a51 | ||
|
412f346ac8 | ||
|
8107a80c4c |
16
CHANGELOG.md
16
CHANGELOG.md
@@ -2,6 +2,22 @@
|
||||
|
||||
Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
||||
|
||||
## [4.3.7]
|
||||
|
||||
### Added
|
||||
|
||||
- Added `.exprdelserv` (.exds) to completement .exas. Deletes an expression on the current server and is susceptible to .dpo, unlike .exd
|
||||
- Added `.shopreq` which lets you set role requirement for specific shop items
|
||||
- Added `.shopbuy` alias to `.buy`
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `.convertlist` showing currencies twice (this may not apply to existing users and it may require you to manually remove all currencies from units.json)
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed `Viewer` field from stream online notification as it is (almost?) always 0.
|
||||
|
||||
## [4.3.6] - 08.09.2022
|
||||
|
||||
### Added
|
||||
|
@@ -24,6 +24,7 @@ public class ShopEntry : DbEntity, IIndexed
|
||||
|
||||
//list
|
||||
public HashSet<ShopEntryItem> Items { get; set; } = new();
|
||||
public ulong? RoleRequirement { get; set; }
|
||||
}
|
||||
|
||||
public class ShopEntryItem : DbEntity
|
||||
|
3550
src/NadekoBot/Migrations/Mysql/20220913192520_shop-role-req.Designer.cs
generated
Normal file
3550
src/NadekoBot/Migrations/Mysql/20220913192520_shop-role-req.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.Mysql
|
||||
{
|
||||
public partial class shoprolereq : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<ulong>(
|
||||
name: "rolerequirement",
|
||||
table: "shopentry",
|
||||
type: "bigint unsigned",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "rolerequirement",
|
||||
table: "shopentry");
|
||||
}
|
||||
}
|
||||
}
|
3548
src/NadekoBot/Migrations/Mysql/MysqlContextModelSnapshot.cs
Normal file
3548
src/NadekoBot/Migrations/Mysql/MysqlContextModelSnapshot.cs
Normal file
File diff suppressed because it is too large
Load Diff
3694
src/NadekoBot/Migrations/PostgreSql/20220913192529_shop-role-req.Designer.cs
generated
Normal file
3694
src/NadekoBot/Migrations/PostgreSql/20220913192529_shop-role-req.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations.PostgreSql
|
||||
{
|
||||
public partial class shoprolereq : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "rolerequirement",
|
||||
table: "shopentry",
|
||||
type: "numeric(20,0)",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "rolerequirement",
|
||||
table: "shopentry");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
2849
src/NadekoBot/Migrations/Sqlite/20220913190532_shop-role-req.Designer.cs
generated
Normal file
2849
src/NadekoBot/Migrations/Sqlite/20220913190532_shop-role-req.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
public partial class shoprolereq : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<ulong>(
|
||||
name: "RoleRequirement",
|
||||
table: "ShopEntry",
|
||||
type: "INTEGER",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "RoleRequirement",
|
||||
table: "ShopEntry");
|
||||
}
|
||||
}
|
||||
}
|
@@ -1745,6 +1745,9 @@ namespace NadekoBot.Migrations
|
||||
b.Property<string>("RoleName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong?>("RoleRequirement")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
@@ -67,42 +67,52 @@ public partial class Administration
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[BotPerm(GuildPerm.ManageRoles)]
|
||||
public async Task ReactionRolesList()
|
||||
public async Task ReactionRolesList(int page = 1)
|
||||
{
|
||||
if (--page < 0)
|
||||
return;
|
||||
|
||||
var reros = await _rero.GetReactionRolesAsync(ctx.Guild.Id);
|
||||
|
||||
var embed = _eb.Create(ctx)
|
||||
.WithOkColor();
|
||||
|
||||
var content = string.Empty;
|
||||
foreach (var g in reros.GroupBy(x => x.MessageId).OrderBy(x => x.Key))
|
||||
await ctx.SendPaginatedConfirmAsync(page, curPage =>
|
||||
{
|
||||
var messageId = g.Key;
|
||||
content +=
|
||||
$"[{messageId}](https://discord.com/channels/{ctx.Guild.Id}/{g.First().ChannelId}/{g.Key})\n";
|
||||
var embed = _eb.Create(ctx)
|
||||
.WithOkColor();
|
||||
|
||||
var groupGroups = g.GroupBy(x => x.Group);
|
||||
|
||||
foreach (var ggs in groupGroups)
|
||||
var content = string.Empty;
|
||||
foreach (var g in reros.OrderBy(x => x.Group)
|
||||
.Skip(curPage * 10)
|
||||
.GroupBy(x => x.MessageId)
|
||||
.OrderBy(x => x.Key))
|
||||
{
|
||||
content += $"`< {(g.Key == 0 ? ("Not Exclusive (Group 0)") : ($"Group {ggs.Key}"))} >`\n";
|
||||
var messageId = g.Key;
|
||||
content +=
|
||||
$"[{messageId}](https://discord.com/channels/{ctx.Guild.Id}/{g.First().ChannelId}/{g.Key})\n";
|
||||
|
||||
foreach (var rero in ggs)
|
||||
var groupGroups = g.GroupBy(x => x.Group);
|
||||
|
||||
foreach (var ggs in groupGroups)
|
||||
{
|
||||
content += $"\t{rero.Emote} -> {(ctx.Guild.GetRole(rero.RoleId)?.Mention ?? "<missing role>")}";
|
||||
if (rero.LevelReq > 0)
|
||||
content += $" (lvl {rero.LevelReq}+)";
|
||||
content += '\n';
|
||||
content += $"`< {(g.Key == 0 ? ("Not Exclusive (Group 0)") : ($"Group {ggs.Key}"))} >`\n";
|
||||
|
||||
foreach (var rero in ggs)
|
||||
{
|
||||
content +=
|
||||
$"\t{rero.Emote} -> {(ctx.Guild.GetRole(rero.RoleId)?.Mention ?? "<missing role>")}";
|
||||
if (rero.LevelReq > 0)
|
||||
content += $" (lvl {rero.LevelReq}+)";
|
||||
content += '\n';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
embed.WithDescription(string.IsNullOrWhiteSpace(content)
|
||||
? "There are no reaction roles on this server"
|
||||
: content);
|
||||
|
||||
embed.WithDescription(string.IsNullOrWhiteSpace(content)
|
||||
? "There are no reaction roles on this server"
|
||||
: content);
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
return embed;
|
||||
}, reros.Count, 10);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@@ -160,15 +160,8 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
found.Response.TrimTo(1000).Replace("](", "]\\(")));
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task ExprDelete(kwum id)
|
||||
public async Task ExprDeleteInternalAsync(kwum id)
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||
return;
|
||||
}
|
||||
|
||||
var ex = await _service.DeleteAsync(ctx.Guild?.Id, id);
|
||||
|
||||
if (ex is not null)
|
||||
@@ -186,6 +179,24 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ExprDeleteServer(kwum id)
|
||||
=> await ExprDeleteInternalAsync(id);
|
||||
|
||||
[Cmd]
|
||||
public async Task ExprDelete(kwum id)
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||
return;
|
||||
}
|
||||
|
||||
await ExprDeleteInternalAsync(id);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task ExprReact(kwum id, params string[] emojiStrs)
|
||||
{
|
||||
|
@@ -38,4 +38,6 @@ public interface IShopService
|
||||
/// <param name="toIndex">Destination index of the entry</param>
|
||||
/// <returns>Whether swap was successful</returns>
|
||||
Task<bool> MoveEntryAsync(ulong guildId, int fromIndex, int toIndex);
|
||||
|
||||
Task<bool> SetItemRoleRequirementAsync(ulong guildId, int index, ulong? roleId);
|
||||
}
|
@@ -98,6 +98,23 @@ public partial class Gambling
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.RoleRequirement is ulong reqRoleId)
|
||||
{
|
||||
var role = ctx.Guild.GetRole(reqRoleId);
|
||||
if (role is null)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.shop_item_req_role_not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
if (!guser.RoleIds.Contains(reqRoleId))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.shop_item_req_role_unfulfilled(Format.Bold(role.ToString())));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.Type == ShopEntryType.Role)
|
||||
{
|
||||
var guser = (IGuildUser)ctx.User;
|
||||
@@ -412,6 +429,27 @@ public partial class Gambling
|
||||
await ctx.ErrorAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task ShopReq(int itemIndex, [Leftover] IRole role = null)
|
||||
{
|
||||
if (--itemIndex < 0)
|
||||
return;
|
||||
|
||||
var succ = await _service.SetItemRoleRequirementAsync(ctx.Guild.Id, itemIndex, role?.Id);
|
||||
if (!succ)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.shop_item_not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
if (role is null)
|
||||
await ReplyConfirmLocalizedAsync(strs.shop_item_role_no_req(itemIndex));
|
||||
else
|
||||
await ReplyConfirmLocalizedAsync(strs.shop_item_role_req(itemIndex + 1, role));
|
||||
}
|
||||
|
||||
public IEmbedBuilder EntryToEmbed(ShopEntry entry)
|
||||
{
|
||||
var embed = _eb.Create().WithOkColor();
|
||||
@@ -443,11 +481,17 @@ public partial class Gambling
|
||||
|
||||
public string EntryToString(ShopEntry entry)
|
||||
{
|
||||
var prepend = string.Empty;
|
||||
if (entry.RoleRequirement is not null)
|
||||
prepend = Format.Italics(GetText(strs.shop_item_requires_role($"<@&{entry.RoleRequirement}>")))
|
||||
+ Environment.NewLine;
|
||||
|
||||
if (entry.Type == ShopEntryType.Role)
|
||||
return GetText(strs.shop_role(Format.Bold(ctx.Guild.GetRole(entry.RoleId)?.Name ?? "MISSING_ROLE")));
|
||||
return prepend
|
||||
+ GetText(strs.shop_role(Format.Bold(ctx.Guild.GetRole(entry.RoleId)?.Name ?? "MISSING_ROLE")));
|
||||
if (entry.Type == ShopEntryType.List)
|
||||
return GetText(strs.unique_items_left(entry.Items.Count)) + "\n" + entry.Name;
|
||||
return "";
|
||||
return prepend + GetText(strs.unique_items_left(entry.Items.Count)) + "\n" + entry.Name;
|
||||
return prepend;
|
||||
}
|
||||
}
|
||||
}
|
@@ -94,4 +94,20 @@ public class ShopService : IShopService, INService
|
||||
await uow.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> SetItemRoleRequirementAsync(ulong guildId, int index, ulong? roleId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var entries = GetEntriesInternal(uow, guildId);
|
||||
|
||||
if (index >= entries.Count)
|
||||
return false;
|
||||
|
||||
var entry = entries[index];
|
||||
|
||||
entry.RoleRequirement = roleId;
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,6 +1,4 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Nadeko.Common;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
@@ -12,95 +10,6 @@ using NadekoBot.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Services;
|
||||
|
||||
public sealed class StreamOnlineMessageDeleterService : INService, IReadyExecutor
|
||||
{
|
||||
private readonly StreamNotificationService _notifService;
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IPubSub _pubSub;
|
||||
|
||||
public StreamOnlineMessageDeleterService(
|
||||
StreamNotificationService notifService,
|
||||
DbService db,
|
||||
IPubSub pubSub,
|
||||
DiscordSocketClient client)
|
||||
{
|
||||
_notifService = notifService;
|
||||
_db = db;
|
||||
_client = client;
|
||||
_pubSub = pubSub;
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
_notifService.OnlineMessagesSent += OnOnlineMessagesSent;
|
||||
|
||||
if(_client.ShardId == 0)
|
||||
await _pubSub.Sub(_notifService.StreamsOfflineKey, OnStreamsOffline);
|
||||
}
|
||||
|
||||
private async Task OnOnlineMessagesSent(FollowedStream.FType type, string name, IReadOnlyCollection<(ulong, ulong)> pairs)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
foreach (var (channelId, messageId) in pairs)
|
||||
{
|
||||
await ctx.GetTable<StreamOnlineMessage>()
|
||||
.InsertAsync(() => new()
|
||||
{
|
||||
Name = name,
|
||||
Type = type,
|
||||
MessageId = messageId,
|
||||
ChannelId = channelId,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnStreamsOffline(List<StreamData> streamDatas)
|
||||
{
|
||||
if (_client.ShardId != 0)
|
||||
return;
|
||||
|
||||
var pairs = await GetMessagesToDelete(streamDatas);
|
||||
|
||||
foreach (var (channelId, messageId) in pairs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var textChannel = await _client.GetChannelAsync(channelId) as ITextChannel;
|
||||
if (textChannel is null)
|
||||
continue;
|
||||
|
||||
await textChannel.DeleteMessageAsync(messageId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<(ulong, ulong)>> GetMessagesToDelete(List<StreamData> streamDatas)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
var toReturn = new List<(ulong, ulong)>();
|
||||
foreach (var sd in streamDatas)
|
||||
{
|
||||
var key = sd.CreateKey();
|
||||
var toDelete = await ctx.GetTable<StreamOnlineMessage>()
|
||||
.Where(x => (x.Type == key.Type && x.Name == key.Name)
|
||||
|| Sql.DateDiff(Sql.DateParts.Day, x.DateAdded, DateTime.UtcNow) > 1)
|
||||
.DeleteWithOutputAsync();
|
||||
|
||||
toReturn.AddRange(toDelete.Select(x => (x.ChannelId, x.MessageId)));
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
{
|
||||
private readonly DbService _db;
|
||||
@@ -370,7 +279,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
|
||||
var message = string.IsNullOrWhiteSpace(fs.Message) ? "" : rep.Replace(fs.Message);
|
||||
|
||||
var msg = await textChannel.EmbedAsync(GetEmbed(fs.GuildId, stream), message);
|
||||
var msg = await textChannel.EmbedAsync(GetEmbed(fs.GuildId, stream, false), message);
|
||||
|
||||
// only cache the ids of channel/message pairs
|
||||
if(_deleteOnOfflineServers.Contains(fs.GuildId))
|
||||
@@ -563,18 +472,22 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
return data;
|
||||
}
|
||||
|
||||
public IEmbedBuilder GetEmbed(ulong guildId, StreamData status)
|
||||
public IEmbedBuilder GetEmbed(ulong guildId, StreamData status, bool showViewers = true)
|
||||
{
|
||||
var embed = _eb.Create()
|
||||
.WithTitle(status.Name)
|
||||
.WithUrl(status.StreamUrl)
|
||||
.WithDescription(status.StreamUrl)
|
||||
.AddField(GetText(guildId, strs.status), status.IsLive ? "🟢 Online" : "🔴 Offline", true)
|
||||
.AddField(GetText(guildId, strs.viewers),
|
||||
status.Viewers == 0 && !status.IsLive
|
||||
? "-"
|
||||
: status.Viewers,
|
||||
true);
|
||||
.AddField(GetText(guildId, strs.status), status.IsLive ? "🟢 Online" : "🔴 Offline", true);
|
||||
|
||||
if (showViewers)
|
||||
{
|
||||
embed.AddField(GetText(guildId, strs.viewers),
|
||||
status.Viewers == 0 && !status.IsLive
|
||||
? "-"
|
||||
: status.Viewers,
|
||||
true);
|
||||
}
|
||||
|
||||
if (status.IsLive)
|
||||
embed = embed.WithOkColor();
|
||||
|
@@ -0,0 +1,99 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Searches.Common;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Services;
|
||||
|
||||
public sealed class StreamOnlineMessageDeleterService : INService, IReadyExecutor
|
||||
{
|
||||
private readonly StreamNotificationService _notifService;
|
||||
private readonly DbService _db;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IPubSub _pubSub;
|
||||
|
||||
public StreamOnlineMessageDeleterService(
|
||||
StreamNotificationService notifService,
|
||||
DbService db,
|
||||
IPubSub pubSub,
|
||||
DiscordSocketClient client)
|
||||
{
|
||||
_notifService = notifService;
|
||||
_db = db;
|
||||
_client = client;
|
||||
_pubSub = pubSub;
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
_notifService.OnlineMessagesSent += OnOnlineMessagesSent;
|
||||
|
||||
if (_client.ShardId == 0)
|
||||
await _pubSub.Sub(_notifService.StreamsOfflineKey, OnStreamsOffline);
|
||||
}
|
||||
|
||||
private async Task OnOnlineMessagesSent(
|
||||
FollowedStream.FType type,
|
||||
string name,
|
||||
IReadOnlyCollection<(ulong, ulong)> pairs)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
foreach (var (channelId, messageId) in pairs)
|
||||
{
|
||||
await ctx.GetTable<StreamOnlineMessage>()
|
||||
.InsertAsync(() => new()
|
||||
{
|
||||
Name = name,
|
||||
Type = type,
|
||||
MessageId = messageId,
|
||||
ChannelId = channelId,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnStreamsOffline(List<StreamData> streamDatas)
|
||||
{
|
||||
if (_client.ShardId != 0)
|
||||
return;
|
||||
|
||||
var pairs = await GetMessagesToDelete(streamDatas);
|
||||
|
||||
foreach (var (channelId, messageId) in pairs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var textChannel = await _client.GetChannelAsync(channelId) as ITextChannel;
|
||||
if (textChannel is null)
|
||||
continue;
|
||||
|
||||
await textChannel.DeleteMessageAsync(messageId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<(ulong, ulong)>> GetMessagesToDelete(List<StreamData> streamDatas)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
var toReturn = new List<(ulong, ulong)>();
|
||||
foreach (var sd in streamDatas)
|
||||
{
|
||||
var key = sd.CreateKey();
|
||||
var toDelete = await ctx.GetTable<StreamOnlineMessage>()
|
||||
.Where(x => (x.Type == key.Type && x.Name == key.Name)
|
||||
|| Sql.DateDiff(Sql.DateParts.Day, x.DateAdded, DateTime.UtcNow) > 1)
|
||||
.DeleteWithOutputAsync();
|
||||
|
||||
toReturn.AddRange(toDelete.Select(x => (x.ChannelId, x.MessageId)));
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ namespace NadekoBot.Services;
|
||||
|
||||
public sealed class StatsService : IStatsService, IReadyExecutor, INService
|
||||
{
|
||||
public const string BOT_VERSION = "4.3.6";
|
||||
public const string BOT_VERSION = "4.3.7";
|
||||
|
||||
public string Author
|
||||
=> "Kwoth#2452";
|
||||
|
@@ -1003,7 +1003,10 @@ shopswap:
|
||||
shopmove:
|
||||
- shopmove
|
||||
buy:
|
||||
- shopbuy
|
||||
- buy
|
||||
shopreq:
|
||||
- shopreq
|
||||
gamevoicechannel:
|
||||
- gamevoicechannel
|
||||
- gvc
|
||||
@@ -1309,6 +1312,10 @@ exprdelete:
|
||||
- exd
|
||||
- exdel
|
||||
- dcr
|
||||
exprdeleteserver:
|
||||
- exprdelserv
|
||||
- exds
|
||||
- exdelserv
|
||||
exprclear:
|
||||
- exprclear
|
||||
- exc
|
||||
|
@@ -27,7 +27,7 @@ greetdel:
|
||||
- "0"
|
||||
- "30"
|
||||
greet:
|
||||
desc: "Toggles anouncements on the current channel when someone joins the server."
|
||||
desc: "Toggles announcements on the current channel when someone joins the server."
|
||||
args:
|
||||
- ""
|
||||
greetmsg:
|
||||
@@ -40,7 +40,7 @@ greetmsg:
|
||||
args:
|
||||
- "Welcome, %user.mention%."
|
||||
bye:
|
||||
desc: "Toggles anouncements on the current channel when someone leaves the server."
|
||||
desc: "Toggles announcements on the current channel when someone leaves the server."
|
||||
args:
|
||||
- ""
|
||||
byemsg:
|
||||
@@ -77,7 +77,7 @@ byetest:
|
||||
- ""
|
||||
- "@SomeoneElse"
|
||||
boost:
|
||||
desc: "Toggles anouncements on the current channel when someone boosts the server."
|
||||
desc: "Toggles announcements on the current channel when someone boosts the server."
|
||||
args:
|
||||
- ""
|
||||
boostmsg:
|
||||
@@ -217,13 +217,17 @@ exprlist:
|
||||
- "1"
|
||||
- "all"
|
||||
exprshow:
|
||||
desc: "Shows a expression's response on a given ID."
|
||||
desc: "Shows an expression's response on a given ID."
|
||||
args:
|
||||
- "1"
|
||||
exprdelete:
|
||||
desc: "Deletes a expression on a specific index. If ran in DM, it is bot owner only and deletes a global expression. If ran in a server, it requires Administration privileges and removes server expression."
|
||||
desc: "Deletes an expression on a specific index. If ran in DM, it is bot owner only and deletes a global expression. If ran in a server, it requires Administration privileges and removes server expression."
|
||||
args:
|
||||
- "5"
|
||||
exprdeleteserver:
|
||||
desc: "Deletes an expression on a specific index on this server."
|
||||
args:
|
||||
- "5c"
|
||||
exprclear:
|
||||
desc: "Deletes all expression on this server."
|
||||
args:
|
||||
@@ -906,7 +910,7 @@ playlists:
|
||||
args:
|
||||
- "1"
|
||||
playlistshow:
|
||||
desc: "Lists all songs in a playlist spepcified by its id. Paginated, 20 per page."
|
||||
desc: "Lists all songs in a playlist specified by its id. Paginated, 20 per page."
|
||||
args:
|
||||
- "1"
|
||||
deleteplaylist:
|
||||
@@ -962,7 +966,7 @@ convertlist:
|
||||
args:
|
||||
- ""
|
||||
wowjoke:
|
||||
desc: "Get one of Kwoth's penultimate WoW jokes."
|
||||
desc: "Get one of penultimate WoW jokes."
|
||||
args:
|
||||
- ""
|
||||
calculate:
|
||||
@@ -992,7 +996,7 @@ pokemonability:
|
||||
args:
|
||||
- "overgrow"
|
||||
memelist:
|
||||
desc: "Shows a list of template keys (and their repspective names) used for `{0}memegen`."
|
||||
desc: "Shows a list of template keys (and their respective names) used for `{0}memegen`."
|
||||
args:
|
||||
- ""
|
||||
memegen:
|
||||
@@ -1097,7 +1101,7 @@ wiki:
|
||||
args:
|
||||
- "query"
|
||||
color:
|
||||
desc: "Shows you pictures of colors which correspond to the inputed hex values. Max 10."
|
||||
desc: "Shows you pictures of colors which correspond to the inputted hex values. Max 10."
|
||||
args:
|
||||
- "00ff00"
|
||||
- "f00 0f0 00f"
|
||||
@@ -1692,7 +1696,7 @@ banprune:
|
||||
args:
|
||||
- "3"
|
||||
wait:
|
||||
desc: "Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands."
|
||||
desc: "Used only as a startup command. Waits a certain number of milliseconds before continuing the execution of the following startup commands."
|
||||
args:
|
||||
- "3000"
|
||||
warnexpire:
|
||||
@@ -1738,6 +1742,11 @@ shopremove:
|
||||
desc: "Removes an item from the shop by its ID."
|
||||
args:
|
||||
- "1"
|
||||
shopreq:
|
||||
desc: "Sets a role which will be required to buy the item on the specified index. Specify only index to remove the requirement."
|
||||
args:
|
||||
- "2 Gamers"
|
||||
- "2"
|
||||
shopchangename:
|
||||
desc: "Change the name of a shop entry at the specified index. Only works for non-role items"
|
||||
args:
|
||||
|
@@ -725,6 +725,11 @@
|
||||
"shop_role_already_bought": "You already bought this role.",
|
||||
"shop_role_purchase": "You've successfully purchased {0} role.",
|
||||
"shop_role_purchase_error": "Error assigning role. Your purchase has been refunded.",
|
||||
"shop_item_role_req": "Shop item #{0} will now require users to have a {1} role in order to purchase it.",
|
||||
"shop_item_req_role_unfulfilled": "You don't have the required role '{0}' in order to buy this shop item.",
|
||||
"shop_item_req_role_not_found": "The required role for this item doesn't exist anymore. Please contact server administrator.",
|
||||
"shop_item_requires_role": "Requires {0} role to purchase",
|
||||
"shop_item_role_no_req": "Shop item #{0} will no longer require a role.",
|
||||
"unique_items_left": "{0} unique items left.",
|
||||
"blocked_commands": "Blocked Commands",
|
||||
"blocked_modules": "Blocked Modules",
|
||||
|
@@ -729,223 +729,6 @@
|
||||
"UnitType": "time",
|
||||
"Modifier": 31536000.0
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"AUD"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 1.4787
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"BGN"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 1.9558
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"BRL"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 3.5991
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"CAD"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 1.4562
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"CHF"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 1.0951
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"CNY"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 7.4565
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"CZK"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 27.025
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"DKK"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 7.4448
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"GBP"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 0.8517
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"HKD"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 8.6631
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"HRK"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 7.4846
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"HUF"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 308.97
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"IDR"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 14814.35
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"ILS"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 4.2241
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"INR"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 74.8703
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"JPY"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 114.27
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"KRW"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 1244.47
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"MXN"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 20.7542
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"MYR"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 4.5205
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"NOK"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 9.2873
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"NZD"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 1.5427
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"PHP"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 51.797
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"PLN"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 4.3436
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"RON"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 4.4505
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"RUB"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 72.4564
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"SEK"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 9.5008
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"SGD"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 1.5196
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"THB"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 38.608
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"TRY"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 3.2977
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"USD"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 1.1168
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"ZAR"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 16.0537
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"K",
|
||||
@@ -970,19 +753,5 @@
|
||||
],
|
||||
"UnitType": "temperature",
|
||||
"Modifier": 0.00
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"EUR"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 1.0
|
||||
},
|
||||
{
|
||||
"Triggers": [
|
||||
"SKK"
|
||||
],
|
||||
"UnitType": "currency",
|
||||
"Modifier": 30.13
|
||||
}
|
||||
]
|
||||
|
Reference in New Issue
Block a user