summaryrefslogtreecommitdiff
path: root/src/SMAPI.Web
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI.Web')
-rw-r--r--src/SMAPI.Web/Controllers/ModsApiController.cs48
-rw-r--r--src/SMAPI.Web/Framework/ModSiteManager.cs28
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)))