mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 09:48:26 -04:00
Finished new response system
This commit is contained in:
@@ -24,7 +24,7 @@ public partial class Searches
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// var embed = new EmbedBuilder()
|
||||
// var embed = _sender.CreateEmbed()
|
||||
// .WithOkColor()
|
||||
// .WithDescription(novelData.Description.Replace("<br>", Environment.NewLine, StringComparison.InvariantCulture))
|
||||
// .WithTitle(novelData.Title)
|
||||
@@ -86,7 +86,7 @@ public partial class Searches
|
||||
.Select(x => x.TextContent.Split(':').Select(y => y.Trim()).ToArray())
|
||||
.ToArray();
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.mal_profile(name)))
|
||||
.AddField("💚 " + GetText(strs.watching), stats[0], true)
|
||||
@@ -151,7 +151,7 @@ public partial class Searches
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithDescription(animeData.Synopsis.Replace("<br>",
|
||||
Environment.NewLine,
|
||||
@@ -183,7 +183,7 @@ public partial class Searches
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithDescription(mangaData.Synopsis.Replace("<br>",
|
||||
Environment.NewLine,
|
||||
|
@@ -35,7 +35,7 @@ public partial class Searches
|
||||
}
|
||||
|
||||
var symbol = symbols.First();
|
||||
var promptEmbed = new EmbedBuilder()
|
||||
var promptEmbed = _sender.CreateEmbed()
|
||||
.WithDescription(symbol.Description)
|
||||
.WithTitle(GetText(strs.did_you_mean(symbol.Symbol)));
|
||||
|
||||
@@ -79,7 +79,7 @@ public partial class Searches
|
||||
|
||||
var price = stock.Price.ToString("C2", localCulture);
|
||||
|
||||
var eb = new EmbedBuilder()
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithAuthor(stock.Symbol)
|
||||
.WithUrl($"https://www.tradingview.com/chart/?symbol={stock.Symbol}")
|
||||
@@ -127,7 +127,7 @@ public partial class Searches
|
||||
|
||||
if (nearest is not null)
|
||||
{
|
||||
var embed = new EmbedBuilder()
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithTitle(GetText(strs.crypto_not_found))
|
||||
.WithDescription(
|
||||
GetText(strs.did_you_mean(Format.Bold($"{nearest.Name} ({nearest.Symbol})"))));
|
||||
@@ -160,7 +160,7 @@ public partial class Searches
|
||||
await using var sparkline = await _service.GetSparklineAsync(crypto.Id, usd.PercentChange7d >= 0);
|
||||
var fileName = $"{crypto.Slug}_7d.png";
|
||||
|
||||
var toSend = new EmbedBuilder()
|
||||
var toSend = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithAuthor($"#{crypto.CmcRank}")
|
||||
.WithTitle($"{crypto.Name} ({crypto.Symbol})")
|
||||
|
@@ -111,28 +111,36 @@ public partial class Searches
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
public async Task FeedList()
|
||||
public async Task FeedList(int page = 1)
|
||||
{
|
||||
if (--page < 0)
|
||||
return;
|
||||
|
||||
var feeds = _service.GetFeeds(ctx.Guild.Id);
|
||||
|
||||
if (!feeds.Any())
|
||||
{
|
||||
await Response().Embed(new EmbedBuilder().WithOkColor().WithDescription(GetText(strs.feed_no_feed))).SendAsync();
|
||||
await Response()
|
||||
.Embed(_sender.CreateEmbed().WithOkColor().WithDescription(GetText(strs.feed_no_feed)))
|
||||
.SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(0,
|
||||
cur =>
|
||||
{
|
||||
var embed = new EmbedBuilder().WithOkColor();
|
||||
var i = 0;
|
||||
var fs = string.Join("\n",
|
||||
feeds.Skip(cur * 10).Take(10).Select(x => $"`{(cur * 10) + ++i}.` <#{x.ChannelId}> {x.Url}"));
|
||||
|
||||
return embed.WithDescription(fs);
|
||||
},
|
||||
feeds.Count,
|
||||
10);
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(feeds)
|
||||
.PageSize(10)
|
||||
.CurrentPage(page)
|
||||
.Page((items, cur) =>
|
||||
{
|
||||
var embed = _sender.CreateEmbed().WithOkColor();
|
||||
var i = 0;
|
||||
var fs = string.Join("\n",
|
||||
items.Select(x => $"`{(cur * 10) + ++i}.` <#{x.ChannelId}> {x.Url}"));
|
||||
|
||||
return embed.WithDescription(fs);
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
}
|
||||
}
|
@@ -31,14 +31,14 @@ public class FeedsService : INService
|
||||
{
|
||||
var guildConfigIds = bot.AllGuildConfigs.Select(x => x.Id).ToList();
|
||||
_subs = uow.Set<GuildConfig>()
|
||||
.AsQueryable()
|
||||
.Where(x => guildConfigIds.Contains(x.Id))
|
||||
.Include(x => x.FeedSubs)
|
||||
.ToList()
|
||||
.SelectMany(x => x.FeedSubs)
|
||||
.GroupBy(x => x.Url.ToLower())
|
||||
.ToDictionary(x => x.Key, x => x.ToList())
|
||||
.ToConcurrent();
|
||||
.AsQueryable()
|
||||
.Where(x => guildConfigIds.Contains(x.Id))
|
||||
.Include(x => x.FeedSubs)
|
||||
.ToList()
|
||||
.SelectMany(x => x.FeedSubs)
|
||||
.GroupBy(x => x.Url.ToLower())
|
||||
.ToDictionary(x => x.Key, x => x.ToList())
|
||||
.ToConcurrent();
|
||||
}
|
||||
|
||||
_client = client;
|
||||
@@ -61,7 +61,7 @@ public class FeedsService : INService
|
||||
// remove from db
|
||||
await using var ctx = _db.GetDbContext();
|
||||
await ctx.GetTable<FeedSub>()
|
||||
.DeleteAsync(x => ids.Contains(x.Id));
|
||||
.DeleteAsync(x => ids.Contains(x.Id));
|
||||
|
||||
// remove from the local cache
|
||||
_subs.TryRemove(url, out _);
|
||||
@@ -95,14 +95,14 @@ public class FeedsService : INService
|
||||
var feed = await FeedReader.ReadAsync(rssUrl);
|
||||
|
||||
var items = feed
|
||||
.Items.Select(item => (Item: item,
|
||||
LastUpdate: item.PublishingDate?.ToUniversalTime()
|
||||
?? (item.SpecificItem as AtomFeedItem)?.UpdatedDate?.ToUniversalTime()))
|
||||
.Where(data => data.LastUpdate is not null)
|
||||
.Select(data => (data.Item, LastUpdate: (DateTime)data.LastUpdate))
|
||||
.OrderByDescending(data => data.LastUpdate)
|
||||
.Reverse() // start from the oldest
|
||||
.ToList();
|
||||
.Items.Select(item => (Item: item,
|
||||
LastUpdate: item.PublishingDate?.ToUniversalTime()
|
||||
?? (item.SpecificItem as AtomFeedItem)?.UpdatedDate?.ToUniversalTime()))
|
||||
.Where(data => data.LastUpdate is not null)
|
||||
.Select(data => (data.Item, LastUpdate: (DateTime)data.LastUpdate))
|
||||
.OrderByDescending(data => data.LastUpdate)
|
||||
.Reverse() // start from the oldest
|
||||
.ToList();
|
||||
|
||||
if (!_lastPosts.TryGetValue(kvp.Key, out var lastFeedUpdate))
|
||||
{
|
||||
@@ -115,7 +115,7 @@ public class FeedsService : INService
|
||||
if (itemUpdateDate <= lastFeedUpdate)
|
||||
continue;
|
||||
|
||||
var embed = new EmbedBuilder().WithFooter(rssUrl);
|
||||
var embed = _sender.CreateEmbed().WithFooter(rssUrl);
|
||||
|
||||
_lastPosts[kvp.Key] = itemUpdateDate;
|
||||
|
||||
@@ -141,12 +141,12 @@ public class FeedsService : INService
|
||||
if (!gotImage && feedItem.SpecificItem is AtomFeedItem afi)
|
||||
{
|
||||
var previewElement = afi.Element.Elements()
|
||||
.FirstOrDefault(x => x.Name.LocalName == "preview");
|
||||
.FirstOrDefault(x => x.Name.LocalName == "preview");
|
||||
|
||||
if (previewElement is null)
|
||||
{
|
||||
previewElement = afi.Element.Elements()
|
||||
.FirstOrDefault(x => x.Name.LocalName == "thumbnail");
|
||||
.FirstOrDefault(x => x.Name.LocalName == "thumbnail");
|
||||
}
|
||||
|
||||
if (previewElement is not null)
|
||||
@@ -170,11 +170,23 @@ public class FeedsService : INService
|
||||
|
||||
//send the created embed to all subscribed channels
|
||||
var feedSendTasks = kvp.Value
|
||||
.Where(x => x.GuildConfig is not null)
|
||||
.Select(x => _client.GetGuild(x.GuildConfig.GuildId)
|
||||
?.GetTextChannel(x.ChannelId)
|
||||
?.EmbedAsync(embed, string.IsNullOrWhiteSpace(x.Message) ? "" : x.Message))
|
||||
.Where(x => x is not null);
|
||||
.Where(x => x.GuildConfig is not null)
|
||||
.Select(x =>
|
||||
{
|
||||
var ch = _client.GetGuild(x.GuildConfig.GuildId)
|
||||
?.GetTextChannel(x.ChannelId);
|
||||
|
||||
if (ch is null)
|
||||
return null;
|
||||
|
||||
return _sender.Response(ch)
|
||||
.Embed(embed)
|
||||
.Text(string.IsNullOrWhiteSpace(x.Message)
|
||||
? string.Empty
|
||||
: x.Message)
|
||||
.SendAsync();
|
||||
})
|
||||
.Where(x => x is not null);
|
||||
|
||||
allSendTasks.Add(feedSendTasks.WhenAll());
|
||||
|
||||
@@ -202,11 +214,15 @@ public class FeedsService : INService
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
return uow.GuildConfigsForId(guildId, set => set.Include(x => x.FeedSubs))
|
||||
.FeedSubs.OrderBy(x => x.Id)
|
||||
.ToList();
|
||||
.FeedSubs.OrderBy(x => x.Id)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public FeedAddResult AddFeed(ulong guildId, ulong channelId, string rssFeed, string message)
|
||||
public FeedAddResult AddFeed(
|
||||
ulong guildId,
|
||||
ulong channelId,
|
||||
string rssFeed,
|
||||
string message)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rssFeed, nameof(rssFeed));
|
||||
|
||||
@@ -252,8 +268,8 @@ public class FeedsService : INService
|
||||
|
||||
using var uow = _db.GetDbContext();
|
||||
var items = uow.GuildConfigsForId(guildId, set => set.Include(x => x.FeedSubs))
|
||||
.FeedSubs.OrderBy(x => x.Id)
|
||||
.ToList();
|
||||
.FeedSubs.OrderBy(x => x.Id)
|
||||
.ToList();
|
||||
|
||||
if (items.Count <= index)
|
||||
return false;
|
||||
|
@@ -40,18 +40,21 @@ public partial class Searches
|
||||
|
||||
var data = JsonConvert.DeserializeObject<List<MemegenTemplate>>(rawJson)!;
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(page,
|
||||
curPage =>
|
||||
{
|
||||
var templates = string.Empty;
|
||||
foreach (var template in data.Skip(curPage * 15).Take(15))
|
||||
templates += $"**{template.Name}:**\n key: `{template.Id}`\n";
|
||||
var embed = new EmbedBuilder().WithOkColor().WithDescription(templates);
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(data)
|
||||
.PageSize(15)
|
||||
.CurrentPage(page)
|
||||
.Page((items, curPage) =>
|
||||
{
|
||||
var templates = string.Empty;
|
||||
foreach (var template in items)
|
||||
templates += $"**{template.Name}:**\n key: `{template.Id}`\n";
|
||||
var embed = _sender.CreateEmbed().WithOkColor().WithDescription(templates);
|
||||
|
||||
return embed;
|
||||
},
|
||||
data.Count,
|
||||
15);
|
||||
return embed;
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@@ -49,7 +49,7 @@ public partial class Searches
|
||||
var obj = objs[0];
|
||||
var userId = obj.UserId;
|
||||
|
||||
await Response().Embed(new EmbedBuilder()
|
||||
await Response().Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle($"osu! {smode} profile for {user}")
|
||||
.WithThumbnailUrl($"https://a.ppy.sh/{userId}")
|
||||
@@ -95,7 +95,7 @@ public partial class Searches
|
||||
var userData = JsonConvert.DeserializeObject<GatariUserResponse>(usrResString).Users[0];
|
||||
var userStats = statsResponse.Stats;
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle($"osu!Gatari {modeStr} profile for {user}")
|
||||
.WithThumbnailUrl($"https://a.gatari.pw/{userStats.Id}")
|
||||
@@ -166,7 +166,7 @@ public partial class Searches
|
||||
return (title, desc);
|
||||
});
|
||||
|
||||
var eb = new EmbedBuilder().WithOkColor().WithTitle($"Top 5 plays for {user}");
|
||||
var eb = _sender.CreateEmbed().WithOkColor().WithTitle($"Top 5 plays for {user}");
|
||||
|
||||
var mapData = await mapTasks.WhenAll();
|
||||
foreach (var (title, desc) in mapData.Where(x => x != default))
|
||||
|
@@ -135,7 +135,7 @@ public partial class Searches
|
||||
}
|
||||
catch
|
||||
{
|
||||
var embed = new EmbedBuilder().WithDescription(GetText(strs.account_not_found)).WithErrorColor();
|
||||
var embed = _sender.CreateEmbed().WithDescription(GetText(strs.account_not_found)).WithErrorColor();
|
||||
|
||||
await Response().Embed(embed).SendAsync();
|
||||
return;
|
||||
@@ -144,37 +144,38 @@ public partial class Searches
|
||||
if (!string.IsNullOrWhiteSpace(league))
|
||||
characters.RemoveAll(c => c.League != league);
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(page,
|
||||
curPage =>
|
||||
{
|
||||
var embed = new EmbedBuilder()
|
||||
.WithAuthor($"Characters on {usr}'s account",
|
||||
"https://web.poecdn.com/image/favicon/ogimage.png",
|
||||
$"{PROFILE_URL}{usr}")
|
||||
.WithOkColor();
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(characters)
|
||||
.PageSize(9)
|
||||
.CurrentPage(page)
|
||||
.Page((items, curPage) =>
|
||||
{
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithAuthor($"Characters on {usr}'s account",
|
||||
"https://web.poecdn.com/image/favicon/ogimage.png",
|
||||
$"{PROFILE_URL}{usr}")
|
||||
.WithOkColor();
|
||||
|
||||
var tempList = characters.Skip(curPage * 9).Take(9).ToList();
|
||||
if (characters.Count == 0)
|
||||
return embed.WithDescription("This account has no characters.");
|
||||
|
||||
if (characters.Count == 0)
|
||||
return embed.WithDescription("This account has no characters.");
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"```{"#",-5}{"Character Name",-23}{"League",-10}{"Class",-13}{"Level",-3}");
|
||||
for (var i = 0; i < items.Count; i++)
|
||||
{
|
||||
var character = items[i];
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"```{"#",-5}{"Character Name",-23}{"League",-10}{"Class",-13}{"Level",-3}");
|
||||
for (var i = 0; i < tempList.Count; i++)
|
||||
{
|
||||
var character = tempList[i];
|
||||
sb.AppendLine(
|
||||
$"#{i + 1 + (curPage * 9),-4}{character.Name,-23}{ShortLeagueName(character.League),-10}{character.Class,-13}{character.Level,-3}");
|
||||
}
|
||||
|
||||
sb.AppendLine(
|
||||
$"#{i + 1 + (curPage * 9),-4}{character.Name,-23}{ShortLeagueName(character.League),-10}{character.Class,-13}{character.Level,-3}");
|
||||
}
|
||||
sb.AppendLine("```");
|
||||
embed.WithDescription(sb.ToString());
|
||||
|
||||
sb.AppendLine("```");
|
||||
embed.WithDescription(sb.ToString());
|
||||
|
||||
return embed;
|
||||
},
|
||||
characters.Count,
|
||||
9);
|
||||
return embed;
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
@@ -190,17 +191,17 @@ public partial class Searches
|
||||
}
|
||||
catch
|
||||
{
|
||||
var eembed = new EmbedBuilder().WithDescription(GetText(strs.leagues_not_found)).WithErrorColor();
|
||||
var eembed = _sender.CreateEmbed().WithDescription(GetText(strs.leagues_not_found)).WithErrorColor();
|
||||
|
||||
await Response().Embed(eembed).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithAuthor("Path of Exile Leagues",
|
||||
"https://web.poecdn.com/image/favicon/ogimage.png",
|
||||
"https://www.pathofexile.com")
|
||||
.WithOkColor();
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithAuthor("Path of Exile Leagues",
|
||||
"https://web.poecdn.com/image/favicon/ogimage.png",
|
||||
"https://www.pathofexile.com")
|
||||
.WithOkColor();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"```{"#",-5}{"League Name",-23}");
|
||||
@@ -273,19 +274,19 @@ public partial class Searches
|
||||
CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithAuthor($"{leagueName} Currency Exchange",
|
||||
"https://web.poecdn.com/image/favicon/ogimage.png",
|
||||
"http://poe.ninja")
|
||||
.AddField("Currency Type", cleanCurrency, true)
|
||||
.AddField($"{cleanConvert} Equivalent", chaosEquivalent / conversionEquivalent, true)
|
||||
.WithOkColor();
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithAuthor($"{leagueName} Currency Exchange",
|
||||
"https://web.poecdn.com/image/favicon/ogimage.png",
|
||||
"http://poe.ninja")
|
||||
.AddField("Currency Type", cleanCurrency, true)
|
||||
.AddField($"{cleanConvert} Equivalent", chaosEquivalent / conversionEquivalent, true)
|
||||
.WithOkColor();
|
||||
|
||||
await Response().Embed(embed).SendAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
var embed = new EmbedBuilder().WithDescription(GetText(strs.ninja_not_found)).WithErrorColor();
|
||||
var embed = _sender.CreateEmbed().WithDescription(GetText(strs.ninja_not_found)).WithErrorColor();
|
||||
|
||||
await Response().Embed(embed).SendAsync();
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ public partial class Searches
|
||||
if (kvp.Key.ToUpperInvariant() == pokemon.ToUpperInvariant())
|
||||
{
|
||||
var p = kvp.Value;
|
||||
await Response().Embed(new EmbedBuilder()
|
||||
await Response().Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(kvp.Key.ToTitleCase())
|
||||
.WithDescription(p.BaseStats.ToString())
|
||||
@@ -55,7 +55,7 @@ public partial class Searches
|
||||
{
|
||||
if (kvp.Key.ToUpperInvariant() == ability)
|
||||
{
|
||||
await Response().Embed(new EmbedBuilder()
|
||||
await Response().Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(kvp.Value.Name)
|
||||
.WithDescription(string.IsNullOrWhiteSpace(kvp.Value.Desc)
|
||||
|
@@ -59,7 +59,7 @@ public partial class Searches
|
||||
|
||||
descStr = descStr.TrimTo(4096);
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithAuthor(ctx.User)
|
||||
.WithTitle(query.TrimTo(64)!)
|
||||
@@ -98,7 +98,7 @@ public partial class Searches
|
||||
|
||||
EmbedBuilder CreateEmbed(IImageSearchResultEntry entry)
|
||||
{
|
||||
return new EmbedBuilder()
|
||||
return _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithAuthor(ctx.User)
|
||||
.WithTitle(query)
|
||||
@@ -190,7 +190,7 @@ public partial class Searches
|
||||
//
|
||||
// var descStr = string.Join("\n\n", desc);
|
||||
//
|
||||
// var embed = new EmbedBuilder()
|
||||
// var embed = _sender.CreateEmbed()
|
||||
// .WithAuthor(ctx.User.ToString(),
|
||||
// "https://upload.wikimedia.org/wikipedia/en/9/90/The_DuckDuckGo_Duck.png")
|
||||
// .WithDescription($"{GetText(strs.search_for)} **{query}**\n\n" + descStr)
|
||||
|
@@ -54,7 +54,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
if (!await ValidateQuery(query))
|
||||
return;
|
||||
|
||||
var embed = new EmbedBuilder();
|
||||
var embed = _sender.CreateEmbed();
|
||||
var data = await _service.GetWeatherDataAsync(query);
|
||||
|
||||
if (data is null)
|
||||
@@ -134,7 +134,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
return;
|
||||
}
|
||||
|
||||
var eb = new EmbedBuilder()
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.time_new))
|
||||
.WithDescription(Format.Code(data.Time.ToString(Culture)))
|
||||
@@ -160,7 +160,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
}
|
||||
|
||||
await Response()
|
||||
.Embed(new EmbedBuilder()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(movie.Title)
|
||||
.WithUrl($"https://www.imdb.com/title/{movie.ImdbId}/")
|
||||
@@ -191,7 +191,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
private Task InternalRandomImage(SearchesService.ImageTag tag)
|
||||
{
|
||||
var url = _service.GetRandomImageUrl(tag);
|
||||
return Response().Embed(new EmbedBuilder().WithOkColor().WithImageUrl(url)).SendAsync();
|
||||
return Response().Embed(_sender.CreateEmbed().WithOkColor().WithImageUrl(url)).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
@@ -242,7 +242,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
}
|
||||
|
||||
await Response()
|
||||
.Embed(new EmbedBuilder()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.AddField(GetText(strs.original_url), $"<{query}>")
|
||||
.AddField(GetText(strs.short_url), $"<{shortLink}>"))
|
||||
@@ -264,7 +264,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(card.Name)
|
||||
.WithDescription(card.Description)
|
||||
@@ -297,7 +297,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder().WithOkColor().WithImageUrl(card.Img);
|
||||
var embed = _sender.CreateEmbed().WithOkColor().WithImageUrl(card.Img);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(card.Flavor))
|
||||
embed.WithDescription(card.Flavor);
|
||||
@@ -318,21 +318,24 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
$"https://api.urbandictionary.com/v0/define?term={Uri.EscapeDataString(query)}");
|
||||
try
|
||||
{
|
||||
var items = JsonConvert.DeserializeObject<UrbanResponse>(res).List;
|
||||
if (items.Any())
|
||||
var allItems = JsonConvert.DeserializeObject<UrbanResponse>(res).List;
|
||||
if (allItems.Any())
|
||||
{
|
||||
await ctx.SendPaginatedConfirmAsync(0,
|
||||
p =>
|
||||
{
|
||||
var item = items[p];
|
||||
return new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithUrl(item.Permalink)
|
||||
.WithTitle(item.Word)
|
||||
.WithDescription(item.Definition);
|
||||
},
|
||||
items.Length,
|
||||
1);
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(allItems)
|
||||
.PageSize(1)
|
||||
.CurrentPage(0)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
var item = items[0];
|
||||
return _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithUrl(item.Permalink)
|
||||
.WithTitle(item.Word)
|
||||
.WithDescription(item.Definition);
|
||||
})
|
||||
.SendAsync();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -362,52 +365,54 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
+ WebUtility.UrlEncode(word));
|
||||
});
|
||||
|
||||
var data = JsonConvert.DeserializeObject<DefineModel>(res);
|
||||
var responseModel = JsonConvert.DeserializeObject<DefineModel>(res);
|
||||
|
||||
var datas = data.Results
|
||||
.Where(x => x.Senses is not null
|
||||
&& x.Senses.Count > 0
|
||||
&& x.Senses[0].Definition is not null)
|
||||
.Select(x => (Sense: x.Senses[0], x.PartOfSpeech))
|
||||
.ToList();
|
||||
var data = responseModel.Results
|
||||
.Where(x => x.Senses is not null
|
||||
&& x.Senses.Count > 0
|
||||
&& x.Senses[0].Definition is not null)
|
||||
.Select(x => (Sense: x.Senses[0], x.PartOfSpeech))
|
||||
.ToList();
|
||||
|
||||
if (!datas.Any())
|
||||
if (!data.Any())
|
||||
{
|
||||
Log.Warning("Definition not found: {Word}", word);
|
||||
await Response().Error(strs.define_unknown).SendAsync();
|
||||
}
|
||||
|
||||
|
||||
var col = datas.Select(x => (
|
||||
Definition: x.Sense.Definition is string
|
||||
? x.Sense.Definition.ToString()
|
||||
: ((JArray)JToken.Parse(x.Sense.Definition.ToString())).First.ToString(),
|
||||
Example: x.Sense.Examples is null || x.Sense.Examples.Count == 0
|
||||
? string.Empty
|
||||
: x.Sense.Examples[0].Text, Word: word,
|
||||
WordType: string.IsNullOrWhiteSpace(x.PartOfSpeech) ? "-" : x.PartOfSpeech))
|
||||
.ToList();
|
||||
var col = data.Select(x => (
|
||||
Definition: x.Sense.Definition is string
|
||||
? x.Sense.Definition.ToString()
|
||||
: ((JArray)JToken.Parse(x.Sense.Definition.ToString())).First.ToString(),
|
||||
Example: x.Sense.Examples is null || x.Sense.Examples.Count == 0
|
||||
? string.Empty
|
||||
: x.Sense.Examples[0].Text, Word: word,
|
||||
WordType: string.IsNullOrWhiteSpace(x.PartOfSpeech) ? "-" : x.PartOfSpeech))
|
||||
.ToList();
|
||||
|
||||
Log.Information("Sending {Count} definition for: {Word}", col.Count, word);
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(0,
|
||||
page =>
|
||||
{
|
||||
var model = col.Skip(page).First();
|
||||
var embed = new EmbedBuilder()
|
||||
.WithDescription(ctx.User.Mention)
|
||||
.AddField(GetText(strs.word), model.Word, true)
|
||||
.AddField(GetText(strs._class), model.WordType, true)
|
||||
.AddField(GetText(strs.definition), model.Definition)
|
||||
.WithOkColor();
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(col)
|
||||
.PageSize(1)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
var model = items.First();
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithDescription(ctx.User.Mention)
|
||||
.AddField(GetText(strs.word), model.Word, true)
|
||||
.AddField(GetText(strs._class), model.WordType, true)
|
||||
.AddField(GetText(strs.definition), model.Definition)
|
||||
.WithOkColor();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(model.Example))
|
||||
embed.AddField(GetText(strs.example), model.Example);
|
||||
if (!string.IsNullOrWhiteSpace(model.Example))
|
||||
embed.AddField(GetText(strs.example), model.Example);
|
||||
|
||||
return embed;
|
||||
},
|
||||
col.Count,
|
||||
1);
|
||||
return embed;
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -474,7 +479,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
|
||||
await Response()
|
||||
.Embed(
|
||||
new EmbedBuilder()
|
||||
_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.AddField("Username", usr.ToString())
|
||||
.AddField("Avatar Url", avatarUrl)
|
||||
@@ -542,7 +547,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
{
|
||||
var v = obj.Verses[0];
|
||||
await Response()
|
||||
.Embed(new EmbedBuilder()
|
||||
.Embed(_sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle($"{v.BookName} {v.Chapter}:{v.Verse}")
|
||||
.WithDescription(v.Text))
|
||||
@@ -565,7 +570,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
||||
return;
|
||||
}
|
||||
|
||||
//var embed = new EmbedBuilder()
|
||||
//var embed = _sender.CreateEmbed()
|
||||
// .WithOkColor()
|
||||
// .WithDescription(gameData.ShortDescription)
|
||||
// .WithTitle(gameData.Name)
|
||||
|
@@ -95,9 +95,9 @@ public partial class Searches
|
||||
.Page((elements, cur) =>
|
||||
{
|
||||
if (elements.Count == 0)
|
||||
return new EmbedBuilder().WithDescription(GetText(strs.streams_none)).WithErrorColor();
|
||||
return _sender.CreateEmbed().WithDescription(GetText(strs.streams_none)).WithErrorColor();
|
||||
|
||||
var eb = new EmbedBuilder().WithTitle(GetText(strs.streams_follow_title)).WithOkColor();
|
||||
var eb = _sender.CreateEmbed().WithTitle(GetText(strs.streams_follow_title)).WithOkColor();
|
||||
for (var index = 0; index < elements.Count; index++)
|
||||
{
|
||||
var elem = elements[index];
|
||||
|
@@ -73,34 +73,34 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
{
|
||||
var ids = client.GetGuildIds();
|
||||
var guildConfigs = uow.Set<GuildConfig>()
|
||||
.AsQueryable()
|
||||
.Include(x => x.FollowedStreams)
|
||||
.Where(x => ids.Contains(x.GuildId))
|
||||
.ToList();
|
||||
.AsQueryable()
|
||||
.Include(x => x.FollowedStreams)
|
||||
.Where(x => ids.Contains(x.GuildId))
|
||||
.ToList();
|
||||
|
||||
_offlineNotificationServers = new(guildConfigs
|
||||
.Where(gc => gc.NotifyStreamOffline)
|
||||
.Select(x => x.GuildId)
|
||||
.ToList());
|
||||
.Where(gc => gc.NotifyStreamOffline)
|
||||
.Select(x => x.GuildId)
|
||||
.ToList());
|
||||
|
||||
_deleteOnOfflineServers = new(guildConfigs
|
||||
.Where(gc => gc.DeleteStreamOnlineMessage)
|
||||
.Select(x => x.GuildId)
|
||||
.ToList());
|
||||
.Where(gc => gc.DeleteStreamOnlineMessage)
|
||||
.Select(x => x.GuildId)
|
||||
.ToList());
|
||||
|
||||
var followedStreams = guildConfigs.SelectMany(x => x.FollowedStreams).ToList();
|
||||
|
||||
_shardTrackedStreams = followedStreams.GroupBy(x => new
|
||||
{
|
||||
x.Type,
|
||||
Name = x.Username.ToLower()
|
||||
})
|
||||
.ToList()
|
||||
.ToDictionary(
|
||||
x => new StreamDataKey(x.Key.Type, x.Key.Name.ToLower()),
|
||||
x => x.GroupBy(y => y.GuildId)
|
||||
.ToDictionary(y => y.Key,
|
||||
y => y.AsEnumerable().ToHashSet()));
|
||||
{
|
||||
x.Type,
|
||||
Name = x.Username.ToLower()
|
||||
})
|
||||
.ToList()
|
||||
.ToDictionary(
|
||||
x => new StreamDataKey(x.Key.Type, x.Key.Name.ToLower()),
|
||||
x => x.GroupBy(y => y.GuildId)
|
||||
.ToDictionary(y => y.Key,
|
||||
y => y.AsEnumerable().ToHashSet()));
|
||||
|
||||
// shard 0 will keep track of when there are no more guilds which track a stream
|
||||
if (client.ShardId == 0)
|
||||
@@ -111,12 +111,12 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
_streamTracker.AddLastData(fs.CreateKey(), null, false);
|
||||
|
||||
_trackCounter = allFollowedStreams.GroupBy(x => new
|
||||
{
|
||||
x.Type,
|
||||
Name = x.Username.ToLower()
|
||||
})
|
||||
.ToDictionary(x => new StreamDataKey(x.Key.Type, x.Key.Name),
|
||||
x => x.Select(fs => fs.GuildId).ToHashSet());
|
||||
{
|
||||
x.Type,
|
||||
Name = x.Username.ToLower()
|
||||
})
|
||||
.ToDictionary(x => new StreamDataKey(x.Key.Type, x.Key.Name),
|
||||
x => x.Select(fs => fs.GuildId).ToHashSet());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
continue;
|
||||
|
||||
var deleteGroups = failingStreams.GroupBy(x => x.Type)
|
||||
.ToDictionary(x => x.Key, x => x.Select(y => y.Name).ToList());
|
||||
.ToDictionary(x => x.Key, x => x.Select(y => y.Name).ToList());
|
||||
|
||||
await using var uow = _db.GetDbContext();
|
||||
foreach (var kvp in deleteGroups)
|
||||
@@ -169,9 +169,9 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
string.Join(", ", kvp.Value));
|
||||
|
||||
var toDelete = uow.Set<FollowedStream>()
|
||||
.AsQueryable()
|
||||
.Where(x => x.Type == kvp.Key && kvp.Value.Contains(x.Username))
|
||||
.ToList();
|
||||
.AsQueryable()
|
||||
.Where(x => x.Type == kvp.Key && kvp.Value.Contains(x.Username))
|
||||
.ToList();
|
||||
|
||||
uow.RemoveRange(toDelete);
|
||||
await uow.SaveChangesAsync();
|
||||
@@ -250,13 +250,20 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
if (_shardTrackedStreams.TryGetValue(key, out var fss))
|
||||
{
|
||||
await fss
|
||||
// send offline stream notifications only to guilds which enable it with .stoff
|
||||
.SelectMany(x => x.Value)
|
||||
.Where(x => _offlineNotificationServers.Contains(x.GuildId))
|
||||
.Select(fs => _client.GetGuild(fs.GuildId)
|
||||
?.GetTextChannel(fs.ChannelId)
|
||||
?.EmbedAsync(GetEmbed(fs.GuildId, stream)))
|
||||
.WhenAll();
|
||||
// send offline stream notifications only to guilds which enable it with .stoff
|
||||
.SelectMany(x => x.Value)
|
||||
.Where(x => _offlineNotificationServers.Contains(x.GuildId))
|
||||
.Select(fs =>
|
||||
{
|
||||
var ch = _client.GetGuild(fs.GuildId)
|
||||
?.GetTextChannel(fs.ChannelId);
|
||||
|
||||
if (ch is null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
return _sender.Response(ch).Embed(GetEmbed(fs.GuildId, stream)).SendAsync();
|
||||
})
|
||||
.WhenAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,33 +277,35 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
if (_shardTrackedStreams.TryGetValue(key, out var fss))
|
||||
{
|
||||
var messages = await fss.SelectMany(x => x.Value)
|
||||
.Select(async fs =>
|
||||
{
|
||||
var textChannel = _client.GetGuild(fs.GuildId)?.GetTextChannel(fs.ChannelId);
|
||||
.Select(async fs =>
|
||||
{
|
||||
var textChannel = _client.GetGuild(fs.GuildId)
|
||||
?.GetTextChannel(fs.ChannelId);
|
||||
|
||||
if (textChannel is null)
|
||||
return default;
|
||||
if (textChannel is null)
|
||||
return default;
|
||||
|
||||
var repCtx = new ReplacementContext(guild: textChannel.Guild, client: _client)
|
||||
.WithOverride("%platform%", () => fs.Type.ToString());
|
||||
var repCtx = new ReplacementContext(guild: textChannel.Guild,
|
||||
client: _client)
|
||||
.WithOverride("%platform%", () => fs.Type.ToString());
|
||||
|
||||
|
||||
var message = string.IsNullOrWhiteSpace(fs.Message)
|
||||
? ""
|
||||
: await _repSvc.ReplaceAsync(fs.Message, repCtx);
|
||||
var message = string.IsNullOrWhiteSpace(fs.Message)
|
||||
? ""
|
||||
: await _repSvc.ReplaceAsync(fs.Message, repCtx);
|
||||
|
||||
var msg = await _sender.Response(textChannel)
|
||||
.Embed(GetEmbed(fs.GuildId, stream, false))
|
||||
.Text(message)
|
||||
.SendAsync();
|
||||
var msg = await _sender.Response(textChannel)
|
||||
.Embed(GetEmbed(fs.GuildId, stream, false))
|
||||
.Text(message)
|
||||
.SendAsync();
|
||||
|
||||
// only cache the ids of channel/message pairs
|
||||
if (_deleteOnOfflineServers.Contains(fs.GuildId))
|
||||
return (textChannel.Id, msg.Id);
|
||||
else
|
||||
return default;
|
||||
})
|
||||
.WhenAll();
|
||||
// only cache the ids of channel/message pairs
|
||||
if (_deleteOnOfflineServers.Contains(fs.GuildId))
|
||||
return (textChannel.Id, msg.Id);
|
||||
else
|
||||
return default;
|
||||
})
|
||||
.WhenAll();
|
||||
|
||||
|
||||
// push online stream messages to redis
|
||||
@@ -306,9 +315,9 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
try
|
||||
{
|
||||
var pairs = messages
|
||||
.Where(x => x != default)
|
||||
.Select(x => (x.Item1, x.Item2))
|
||||
.ToList();
|
||||
.Where(x => x != default)
|
||||
.Select(x => (x.Item1, x.Item2))
|
||||
.ToList();
|
||||
|
||||
if (pairs.Count > 0)
|
||||
await OnlineMessagesSent(key.Type, key.Name, pairs);
|
||||
@@ -330,9 +339,10 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
{
|
||||
using (var uow = _db.GetDbContext())
|
||||
{
|
||||
var gc = uow.Set<GuildConfig>().AsQueryable()
|
||||
.Include(x => x.FollowedStreams)
|
||||
.FirstOrDefault(x => x.GuildId == guildConfig.GuildId);
|
||||
var gc = uow.Set<GuildConfig>()
|
||||
.AsQueryable()
|
||||
.Include(x => x.FollowedStreams)
|
||||
.FirstOrDefault(x => x.GuildId == guildConfig.GuildId);
|
||||
|
||||
if (gc is null)
|
||||
return Task.CompletedTask;
|
||||
@@ -392,10 +402,10 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
var fss = uow.Set<FollowedStream>()
|
||||
.AsQueryable()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.OrderBy(x => x.Id)
|
||||
.ToList();
|
||||
.AsQueryable()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.OrderBy(x => x.Id)
|
||||
.ToList();
|
||||
|
||||
// out of range
|
||||
if (fss.Count <= index)
|
||||
@@ -484,11 +494,11 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
|
||||
public EmbedBuilder GetEmbed(ulong guildId, StreamData status, bool showViewers = true)
|
||||
{
|
||||
var embed = new EmbedBuilder()
|
||||
.WithTitle(status.Name)
|
||||
.WithUrl(status.StreamUrl)
|
||||
.WithDescription(status.StreamUrl)
|
||||
.AddField(GetText(guildId, strs.status), status.IsLive ? "🟢 Online" : "🔴 Offline", true);
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithTitle(status.Name)
|
||||
.WithUrl(status.StreamUrl)
|
||||
.WithDescription(status.StreamUrl)
|
||||
.AddField(GetText(guildId, strs.status), status.IsLive ? "🟢 Online" : "🔴 Offline", true);
|
||||
|
||||
if (showViewers)
|
||||
{
|
||||
|
@@ -69,7 +69,7 @@ public sealed class TranslateService : ITranslateService, IExecNoCommand, IReady
|
||||
|| msg.Content.Equals(output, StringComparison.InvariantCultureIgnoreCase))
|
||||
return;
|
||||
|
||||
var embed = new EmbedBuilder().WithOkColor();
|
||||
var embed = _sender.CreateEmbed().WithOkColor();
|
||||
|
||||
if (autoDelete)
|
||||
{
|
||||
|
@@ -20,7 +20,7 @@ public partial class Searches
|
||||
await ctx.Channel.TriggerTypingAsync();
|
||||
var translation = await _service.Translate(from, to, text);
|
||||
|
||||
var embed = new EmbedBuilder().WithOkColor().AddField(from, text).AddField(to, translation);
|
||||
var embed = _sender.CreateEmbed().WithOkColor().AddField(from, text).AddField(to, translation);
|
||||
|
||||
await Response().Embed(embed).SendAsync();
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public partial class Searches
|
||||
{
|
||||
var langs = _service.GetLanguages().ToList();
|
||||
|
||||
var eb = new EmbedBuilder()
|
||||
var eb = _sender.CreateEmbed()
|
||||
.WithTitle(GetText(strs.supported_languages))
|
||||
.WithOkColor();
|
||||
|
||||
|
@@ -25,7 +25,7 @@ public partial class Searches
|
||||
using var http = _httpFactory.CreateClient();
|
||||
var res = await http.GetStringAsync($"{XKCD_URL}/info.0.json");
|
||||
var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
|
||||
var embed = new EmbedBuilder()
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithImageUrl(comic.ImageLink)
|
||||
.WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{XKCD_URL}/{comic.Num}")
|
||||
@@ -60,7 +60,7 @@ public partial class Searches
|
||||
var res = await http.GetStringAsync($"{XKCD_URL}/{num}/info.0.json");
|
||||
|
||||
var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
|
||||
var embed = new EmbedBuilder()
|
||||
var embed = _sender.CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithImageUrl(comic.ImageLink)
|
||||
.WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{XKCD_URL}/{num}")
|
||||
|
Reference in New Issue
Block a user