diff --git a/docs/release-notes.md b/docs/release-notes.md index c29bc39c..1f394849 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,6 +1,10 @@ ← [README](README.md) # Release notes +## Upcoming release +* For players: + * Fixed CurseForge update checks for the new CurseForge API. + ## 3.14.4 Released 15 May 2022 for Stardew Valley 1.5.6 or later. diff --git a/src/SMAPI.Web/Framework/Clients/CurseForge/CurseForgeClient.cs b/src/SMAPI.Web/Framework/Clients/CurseForge/CurseForgeClient.cs index d351b42d..9b4f2580 100644 --- a/src/SMAPI.Web/Framework/Clients/CurseForge/CurseForgeClient.cs +++ b/src/SMAPI.Web/Framework/Clients/CurseForge/CurseForgeClient.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Net; using System.Text.RegularExpressions; using System.Threading.Tasks; using Pathoschild.Http.Client; @@ -33,9 +34,12 @@ namespace StardewModdingAPI.Web.Framework.Clients.CurseForge /// Construct an instance. /// The user agent for the API client. /// The base URL for the CurseForge API. - public CurseForgeClient(string userAgent, string apiUrl) + /// The API authentication key. + public CurseForgeClient(string userAgent, string apiUrl, string apiKey) { - this.Client = new FluentClient(apiUrl).SetUserAgent(userAgent); + this.Client = new FluentClient(apiUrl) + .SetUserAgent(userAgent) + .AddDefault(request => request.WithHeader("x-api-key", apiKey)); } /// Get update check info about a mod. @@ -49,11 +53,18 @@ namespace StardewModdingAPI.Web.Framework.Clients.CurseForge return page.SetError(RemoteModStatus.DoesNotExist, $"The value '{id}' isn't a valid CurseForge mod ID, must be an integer ID."); // get raw data - ModModel? mod = await this.Client - .GetAsync($"addon/{parsedId}") - .As(); - if (mod == null) + ModModel? mod; + try + { + ResponseModel response = await this.Client + .GetAsync($"mods/{parsedId}") + .As>(); + mod = response.Data; + } + catch (ApiException ex) when (ex.Status == HttpStatusCode.NotFound) + { return page.SetError(RemoteModStatus.DoesNotExist, "Found no CurseForge mod with this ID."); + } // get downloads List downloads = new List(); @@ -65,7 +76,7 @@ namespace StardewModdingAPI.Web.Framework.Clients.CurseForge } // return info - return page.SetInfo(name: mod.Name, version: null, url: mod.WebsiteUrl, downloads: downloads); + return page.SetInfo(name: mod.Name, version: null, url: mod.Links.WebsiteUrl, downloads: downloads); } /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. diff --git a/src/SMAPI.Web/Framework/Clients/CurseForge/ResponseModels/ModLinksModel.cs b/src/SMAPI.Web/Framework/Clients/CurseForge/ResponseModels/ModLinksModel.cs new file mode 100644 index 00000000..2f9abe4f --- /dev/null +++ b/src/SMAPI.Web/Framework/Clients/CurseForge/ResponseModels/ModLinksModel.cs @@ -0,0 +1,7 @@ +namespace StardewModdingAPI.Web.Framework.Clients.CurseForge.ResponseModels +{ + /// A list of links for a mod. + /// The URL for the CurseForge mod page. + /// The URL for the mod's source code, if any. + public record ModLinksModel(string WebsiteUrl, string? SourceUrl); +} diff --git a/src/SMAPI.Web/Framework/Clients/CurseForge/ResponseModels/ModModel.cs b/src/SMAPI.Web/Framework/Clients/CurseForge/ResponseModels/ModModel.cs index fd7796f2..7018be54 100644 --- a/src/SMAPI.Web/Framework/Clients/CurseForge/ResponseModels/ModModel.cs +++ b/src/SMAPI.Web/Framework/Clients/CurseForge/ResponseModels/ModModel.cs @@ -1,38 +1,9 @@ namespace StardewModdingAPI.Web.Framework.Clients.CurseForge.ResponseModels { - /// An mod from the CurseForge API. - public class ModModel - { - /********* - ** Accessors - *********/ - /// The mod's unique ID on CurseForge. - public int ID { get; } - - /// The mod name. - public string Name { get; } - - /// The web URL for the mod page. - public string WebsiteUrl { get; } - - /// The available file downloads. - public ModFileModel[] LatestFiles { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The mod's unique ID on CurseForge. - /// The mod name. - /// The web URL for the mod page. - /// The available file downloads. - public ModModel(int id, string name, string websiteUrl, ModFileModel[] latestFiles) - { - this.ID = id; - this.Name = name; - this.WebsiteUrl = websiteUrl; - this.LatestFiles = latestFiles; - } - } + /// A mod from the CurseForge API. + /// The mod's unique ID on CurseForge. + /// The mod name. + /// The available file downloads. + /// The URLs for this mod. + public record ModModel(int Id, string Name, ModFileModel[] LatestFiles, ModLinksModel Links); } diff --git a/src/SMAPI.Web/Framework/Clients/CurseForge/ResponseModels/ResponseModel.cs b/src/SMAPI.Web/Framework/Clients/CurseForge/ResponseModels/ResponseModel.cs new file mode 100644 index 00000000..4d538a93 --- /dev/null +++ b/src/SMAPI.Web/Framework/Clients/CurseForge/ResponseModels/ResponseModel.cs @@ -0,0 +1,8 @@ +using Newtonsoft.Json; + +namespace StardewModdingAPI.Web.Framework.Clients.CurseForge.ResponseModels +{ + /// A response from the CurseForge API. + /// The data returned by the API. + public record ResponseModel(TData Data); +} diff --git a/src/SMAPI.Web/Framework/ConfigModels/ApiClientsConfig.cs b/src/SMAPI.Web/Framework/ConfigModels/ApiClientsConfig.cs index b582b2b0..ebb3618a 100644 --- a/src/SMAPI.Web/Framework/ConfigModels/ApiClientsConfig.cs +++ b/src/SMAPI.Web/Framework/ConfigModels/ApiClientsConfig.cs @@ -42,6 +42,9 @@ namespace StardewModdingAPI.Web.Framework.ConfigModels /// The base URL for the CurseForge API. public string CurseForgeBaseUrl { get; set; } = null!; + /// The API authentication key for the CurseForge API. + public string CurseForgeApiKey { get; set; } = null!; + /**** ** GitHub diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs index 2693aa90..9980d00c 100644 --- a/src/SMAPI.Web/Startup.cs +++ b/src/SMAPI.Web/Startup.cs @@ -111,7 +111,8 @@ namespace StardewModdingAPI.Web services.AddSingleton(new CurseForgeClient( userAgent: userAgent, - apiUrl: api.CurseForgeBaseUrl + apiUrl: api.CurseForgeBaseUrl, + apiKey: api.CurseForgeApiKey )); services.AddSingleton(new GitHubClient( diff --git a/src/SMAPI.Web/appsettings.json b/src/SMAPI.Web/appsettings.json index 1231f824..10fcbe9c 100644 --- a/src/SMAPI.Web/appsettings.json +++ b/src/SMAPI.Web/appsettings.json @@ -31,7 +31,8 @@ "ChucklefishBaseUrl": "https://community.playstarbound.com", "ChucklefishModPageUrlFormat": "resources/{0}", - "CurseForgeBaseUrl": "https://addons-ecs.forgesvc.net/api/v2/", + "CurseForgeBaseUrl": "https://api.curseforge.com/v1/", + "CurseForgeApiKey": null, "GitHubBaseUrl": "https://api.github.com", "GitHubAcceptHeader": "application/vnd.github.v3+json",