diff options
Diffstat (limited to 'src/SMAPI.Web')
-rw-r--r-- | src/SMAPI.Web/Controllers/ModsApiController.cs | 48 | ||||
-rw-r--r-- | src/SMAPI.Web/Framework/ModSiteManager.cs | 28 |
2 files changed, 51 insertions, 25 deletions
diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs index 14be520d..028fc613 100644 --- a/src/SMAPI.Web/Controllers/ModsApiController.cs +++ b/src/SMAPI.Web/Controllers/ModsApiController.cs @@ -135,7 +135,7 @@ namespace StardewModdingAPI.Web.Controllers // validate update key if (!updateKey.LooksValid) { - errors.Add($"The update key '{updateKey}' isn't in a valid format. It should contain the site key and mod ID like 'Nexus:541'."); + errors.Add($"The update key '{updateKey}' isn't in a valid format. It should contain the site key and mod ID like 'Nexus:541', with an optional subkey like 'Nexus:541@subkey'."); continue; } @@ -271,7 +271,7 @@ namespace StardewModdingAPI.Web.Controllers } // get version info - return this.ModSites.GetPageVersions(page, allowNonStandardVersions, mapRemoteVersions); + return this.ModSites.GetPageVersions(page, updateKey.Subkey, allowNonStandardVersions, mapRemoteVersions); } /// <summary>Get update keys based on the available mod metadata, while maintaining the precedence order.</summary> @@ -280,44 +280,56 @@ namespace StardewModdingAPI.Web.Controllers /// <param name="entry">The mod's entry in the wiki list.</param> private IEnumerable<UpdateKey> GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry) { + // get every update key (including duplicates) IEnumerable<string> GetRaw() { // specified update keys if (specifiedKeys != null) { foreach (string key in specifiedKeys) - yield return key?.Trim(); + { + if (!string.IsNullOrWhiteSpace(key)) + yield return key.Trim(); + } } // default update key string defaultKey = record?.GetDefaultUpdateKey(); - if (defaultKey != null) + if (!string.IsNullOrWhiteSpace(defaultKey)) yield return defaultKey; // wiki metadata if (entry != null) { if (entry.NexusID.HasValue) - yield return UpdateKey.GetString(ModSiteKey.Nexus, entry.NexusID?.ToString()); + yield return UpdateKey.GetString(ModSiteKey.Nexus, entry.NexusID.ToString()); if (entry.ModDropID.HasValue) - yield return UpdateKey.GetString(ModSiteKey.ModDrop, entry.ModDropID?.ToString()); + yield return UpdateKey.GetString(ModSiteKey.ModDrop, entry.ModDropID.ToString()); if (entry.CurseForgeID.HasValue) - yield return UpdateKey.GetString(ModSiteKey.CurseForge, entry.CurseForgeID?.ToString()); + yield return UpdateKey.GetString(ModSiteKey.CurseForge, entry.CurseForgeID.ToString()); if (entry.ChucklefishID.HasValue) - yield return UpdateKey.GetString(ModSiteKey.Chucklefish, entry.ChucklefishID?.ToString()); + yield return UpdateKey.GetString(ModSiteKey.Chucklefish, entry.ChucklefishID.ToString()); } } - HashSet<UpdateKey> seen = new HashSet<UpdateKey>(); - foreach (string rawKey in GetRaw()) - { - if (string.IsNullOrWhiteSpace(rawKey)) - continue; - - UpdateKey key = UpdateKey.Parse(rawKey); - if (seen.Add(key)) - yield return key; - } + // get unique update keys + var subkeyRoots = new HashSet<UpdateKey>(); + List<UpdateKey> updateKeys = GetRaw() + .Select(raw => + { + var key = UpdateKey.Parse(raw); + if (key.Subkey != null) + subkeyRoots.Add(new UpdateKey(key.Site, key.ID, null)); + return key; + }) + .Distinct() + .ToList(); + + // if the list has both an update key (like "Nexus:2400") and subkey (like "Nexus:2400@subkey") for the same page, the subkey takes priority + if (subkeyRoots.Any()) + updateKeys.RemoveAll(subkeyRoots.Contains); + + return updateKeys; } } } diff --git a/src/SMAPI.Web/Framework/ModSiteManager.cs b/src/SMAPI.Web/Framework/ModSiteManager.cs index eaae7935..68b4c6ac 100644 --- a/src/SMAPI.Web/Framework/ModSiteManager.cs +++ b/src/SMAPI.Web/Framework/ModSiteManager.cs @@ -54,9 +54,10 @@ namespace StardewModdingAPI.Web.Framework /// <summary>Parse version info for the given mod page info.</summary> /// <param name="page">The mod page info.</param> + /// <param name="subkey">The optional update subkey to match in available files. (If no file names or descriptions contain the subkey, it'll be ignored.)</param> /// <param name="mapRemoteVersions">Maps remote versions to a semantic version for update checks.</param> /// <param name="allowNonStandardVersions">Whether to allow non-standard versions.</param> - public ModInfoModel GetPageVersions(IModPage page, bool allowNonStandardVersions, IDictionary<string, string> mapRemoteVersions) + public ModInfoModel GetPageVersions(IModPage page, string subkey, bool allowNonStandardVersions, IDictionary<string, string> mapRemoteVersions) { // get base model ModInfoModel model = new ModInfoModel() @@ -66,7 +67,10 @@ namespace StardewModdingAPI.Web.Framework return model; // fetch versions - if (!this.TryGetLatestVersions(page, allowNonStandardVersions, mapRemoteVersions, out ISemanticVersion mainVersion, out ISemanticVersion previewVersion)) + bool hasVersions = this.TryGetLatestVersions(page, subkey, allowNonStandardVersions, mapRemoteVersions, out ISemanticVersion mainVersion, out ISemanticVersion previewVersion); + if (!hasVersions && subkey != null) + hasVersions = this.TryGetLatestVersions(page, null, allowNonStandardVersions, mapRemoteVersions, out mainVersion, out previewVersion); + if (!hasVersions) return model.SetError(RemoteModStatus.InvalidData, $"The {page.Site} mod with ID '{page.Id}' has no valid versions."); // return info @@ -96,11 +100,12 @@ namespace StardewModdingAPI.Web.Framework *********/ /// <summary>Get the mod version numbers for the given mod.</summary> /// <param name="mod">The mod to check.</param> + /// <param name="subkey">The optional update subkey to match in available files. (If no file names or descriptions contain the subkey, it'll be ignored.)</param> /// <param name="allowNonStandardVersions">Whether to allow non-standard versions.</param> /// <param name="mapRemoteVersions">Maps remote versions to a semantic version for update checks.</param> /// <param name="main">The main mod version.</param> /// <param name="preview">The latest prerelease version, if newer than <paramref name="main"/>.</param> - private bool TryGetLatestVersions(IModPage mod, bool allowNonStandardVersions, IDictionary<string, string> mapRemoteVersions, out ISemanticVersion main, out ISemanticVersion preview) + private bool TryGetLatestVersions(IModPage mod, string subkey, bool allowNonStandardVersions, IDictionary<string, string> mapRemoteVersions, out ISemanticVersion main, out ISemanticVersion preview) { main = null; preview = null; @@ -113,14 +118,23 @@ namespace StardewModdingAPI.Web.Framework if (mod != null) { - // get versions - main = ParseVersion(mod.Version); - foreach (string rawVersion in mod.Downloads.Select(p => p.Version)) + // get mod version + if (subkey == null) + main = ParseVersion(mod.Version); + + // get file versions + foreach (IModDownload download in mod.Downloads) { - ISemanticVersion cur = ParseVersion(rawVersion); + // check for subkey if specified + if (subkey != null && download.Name?.Contains(subkey, StringComparison.OrdinalIgnoreCase) != true && download.Description?.Contains(subkey, StringComparison.OrdinalIgnoreCase) != true) + continue; + + // parse version + ISemanticVersion cur = ParseVersion(download.Version); if (cur == null) continue; + // track highest versions if (main == null || cur.IsNewerThan(main)) main = cur; if (cur.IsPrerelease() && (preview == null || cur.IsNewerThan(preview))) |