Skip to content

Commit 1ec9cbb

Browse files
committed
feat: Ability to search projects for game versions and modloaders (depending on game)
fixes #10
1 parent 236cb86 commit 1ec9cbb

File tree

2 files changed

+98
-12
lines changed

2 files changed

+98
-12
lines changed

CFDiscordBot/CFDiscordBot.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
<None Update="appsettings.json">
2222
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
2323
</None>
24+
<None Update="appsettings.Dev.json">
25+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
26+
</None>
2427
</ItemGroup>
2528

2629
</Project>

CFDiscordBot/Commands/ProjectLookup.cs

Lines changed: 95 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
using Discord;
1+
using CurseForge.APIClient.Models.Mods;
2+
using Discord;
23
using Discord.Interactions;
34
using System.Text;
5+
using System.Text.Json;
46

57
namespace CFDiscordBot.Commands
68
{
@@ -9,7 +11,11 @@ public partial class Lookup
911
[SlashCommand("projectid", "Looks up a project by its ID")]
1012
public async Task ProjectIdAsync(
1113
[Summary("id", "The ID of the project to look up")]
12-
int projectId
14+
int projectId,
15+
[Summary("GameVersion", "The version of the game you want to find info about for this project")]
16+
string? gameVersion = null,
17+
[Summary("Modloader", "The modloader you want to find info about for this project")]
18+
ModLoaderType? modLoader = null
1319
)
1420
{
1521
CurseForge.APIClient.Models.Mods.Mod? mod = null;
@@ -32,6 +38,20 @@ int projectId
3238
return;
3339
}
3440

41+
List<CurseForge.APIClient.Models.Files.File> matchingFiles = new();
42+
43+
bool isFileSearch = false;
44+
45+
if (gameVersion is not null || modLoader is not null)
46+
{
47+
isFileSearch = true;
48+
var fileReq = await apiClient.GetModFilesAsync(projectId, gameVersion, modLoader);
49+
if (fileReq?.Data.Count > 0)
50+
{
51+
matchingFiles.AddRange(fileReq.Data);
52+
}
53+
}
54+
3555
var summaryText = new StringBuilder();
3656

3757
summaryText.AppendLine(mod.Summary);
@@ -43,14 +63,10 @@ int projectId
4363
Fields = []
4464
};
4565

46-
if (Uri.TryCreate(mod.Logo?.ThumbnailUrl, UriKind.Absolute, out var logoUri))
47-
{
48-
projectEmbed.ThumbnailUrl = logoUri.AbsoluteUri;
49-
}
50-
else
51-
{
52-
projectEmbed.ThumbnailUrl = "https://www.curseforge.com/images/flame.svg";
53-
}
66+
projectEmbed.ThumbnailUrl =
67+
Uri.TryCreate(mod.Logo?.ThumbnailUrl, UriKind.Absolute, out var logoUri) ?
68+
logoUri.AbsoluteUri :
69+
"https://www.curseforge.com/images/flame.svg";
5470

5571
var categories = string.Join(", ", mod.Categories.Select(c => $"[{c.Name}]({c.Url})"));
5672

@@ -64,12 +80,79 @@ int projectId
6480
new() { Name = "Mod Distribution", Value = mod.AllowModDistribution ?? true ? "Allowed" : "Not allowed", IsInline = true },
6581
new() { Name = "Is available", Value = mod.IsAvailable ? "Yes" : "No", IsInline = true }
6682
};
83+
84+
if (matchingFiles.Count > 0)
85+
{
86+
List<string> fieldsToRemove = ["Created", "Modified", "Released", "Downloads", "Is available", "Status", "Mod Distribution"];
87+
fields.RemoveAll(m => fieldsToRemove.Any(i => i == m.Name));
88+
89+
var latestFile = matchingFiles.OrderByDescending(f => f.FileDate).First();
90+
91+
fields.AddRange([
92+
new EmbedFieldBuilder { Name = "File Status", Value = latestFile.FileStatus.ToString(), IsInline = true },
93+
new EmbedFieldBuilder { Name = "File Uploaded", Value = $"<t:{latestFile.FileDate.ToUnixTimeSeconds()}:F>", IsInline = true },
94+
new EmbedFieldBuilder { Name = "File Downloads", Value = latestFile.DownloadCount.ToString("n0"), IsInline = true },
95+
new EmbedFieldBuilder { Name = "Mod Distribution", Value = mod.AllowModDistribution ?? true ? "Allowed" : "Not allowed", IsInline = true },
96+
new EmbedFieldBuilder { Name = "File is available", Value = latestFile.IsAvailable ? "Yes" : "No", IsInline = true }
97+
]);
98+
99+
if (mod.GameId == 432)
100+
{
101+
var sides = latestFile.SortableGameVersions
102+
.Where(i => i.GameVersionTypeId is 75208)
103+
.Select(i => i.GameVersionName)
104+
.ToList();
105+
106+
if (sides.Count > 0)
107+
{
108+
fields.Add(new EmbedFieldBuilder { Name = "Environments", Value = string.Join(", ", sides), IsInline = false });
109+
}
110+
111+
var modLoaders = latestFile.SortableGameVersions
112+
.Where(i => i.GameVersionTypeId is 68441)
113+
.Select(i => i.GameVersionName)
114+
.ToList();
115+
116+
if (modLoaders.Count > 0)
117+
{
118+
fields.Add(new EmbedFieldBuilder { Name = "Modloaders", Value = string.Join(", ", modLoaders), IsInline = false });
119+
}
120+
}
121+
122+
var gameVersions = latestFile.SortableGameVersions
123+
.Where(v => !string.IsNullOrWhiteSpace(v.GameVersion))
124+
.OrderByDescending(v => v.GameVersionPadded)
125+
.Select(i => i.GameVersionName)
126+
.ToList();
127+
if (gameVersions.Count > 0)
128+
{
129+
fields.Add(new EmbedFieldBuilder { Name = "Game versions", Value = string.Join(", ", gameVersions), IsInline = false });
130+
}
131+
}
67132

68133
if (!string.IsNullOrWhiteSpace(categories))
69134
{
70135
fields.Add(new EmbedFieldBuilder { Name = "Categories", Value = categories, IsInline = false });
71136
}
72137

138+
139+
140+
if (isFileSearch && matchingFiles.Count == 0)
141+
{
142+
var sb = new StringBuilder();
143+
if (gameVersion is not null)
144+
{
145+
sb.AppendLine($"**Game version** - {gameVersion}");
146+
}
147+
148+
if (modLoader is not null)
149+
{
150+
sb.AppendLine($"**Modloader** - {modLoader}");
151+
}
152+
153+
fields.Add(new EmbedFieldBuilder { Name = "File matching search criteria not found", Value = sb.ToString(), IsInline = false });
154+
}
155+
73156
projectEmbed.Fields.AddRange(fields);
74157

75158
projectEmbed.Footer = new EmbedFooterBuilder
@@ -131,7 +214,7 @@ int projectId
131214
}
132215

133216
// If the game is Minecraft Bedrock, we do an additional check if MCPEDL has the mod available through a slug lookup.
134-
if (mod.GameId == 78022 && mod.AllowModDistribution.HasValue && mod.AllowModDistribution.Value)
217+
if (mod is { GameId: 78022, AllowModDistribution: not null } && mod.AllowModDistribution.Value)
135218
{
136219
var client = httpClientFactory.CreateClient();
137220
client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "CFLookup Discord Bot/1.0; (+cflookup@itssimple.se)");
@@ -155,7 +238,7 @@ await RespondAsync($"Project `{projectId}` is: **[{mod.Name}](https://cflookup.c
155238
components: buttons.Build()
156239
);
157240
}
158-
241+
159242
[SlashCommand("cflookup", "Looks up a project by its ID", ignoreGroupNames: true)]
160243
public async Task CFLookup([Summary("id", "The ID")] int projectId) => await ProjectIdAsync(projectId);
161244
}

0 commit comments

Comments
 (0)