From c916cc5a1023ab81df89458ecb679405081f54c6 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 18 Aug 2018 13:25:08 -0400 Subject: mark old SpaceCore versions incompatible --- src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json b/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json index c95abe75..0a24a376 100644 --- a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json +++ b/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json @@ -1393,7 +1393,8 @@ "SpaceCore": { "ID": "spacechase0.SpaceCore", - "Default | UpdateKey": "Nexus:1348" + "Default | UpdateKey": "Nexus:1348", + "~1.1.2-unofficial.1-defenthenation | Status": "AssumeBroken" // causes .png.xnb content load errors and "MissingMethodException: Method 'DecoratableLocation.getWalls' not found." }, "Speedster": { -- cgit From 5374b216ca62959db384ed243ac51e6209bc2abc Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 22 Aug 2018 01:35:56 -0400 Subject: update compatibility list --- src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json b/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json index 0a24a376..1e9d2e49 100644 --- a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json +++ b/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json @@ -962,6 +962,11 @@ "~1.4 | Status": "AssumeBroken" // broke in SMAPI 2.0 }, + "More Silo Storage": { + "ID": "OrneryWalrus.MoreSiloStorage", + "~1.0.1 | Status": "AssumeBroken" // broke in SDV 1.3 + }, + "More Weapons": { "ID": "Joco80.MoreWeapons", "Default | UpdateKey": "Nexus:1168" @@ -1481,7 +1486,8 @@ "Stephan's Lots of Crops": { "ID": "stephansstardewcrops", "MapRemoteVersions": { "1.41": "1.1" }, // manifest not updated - "Default | UpdateKey": "Chucklefish:4314" + "Default | UpdateKey": "Chucklefish:4314", + "~1.1 | Status": "AssumeBroken" // broke in SDV 1.3 (overwrites vanilla items) }, "Stumps to Hardwood Stumps": { -- cgit From 046c6be68ad5d48e69512116100797a974330d4b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 22 Aug 2018 20:07:14 -0400 Subject: mark Grass Growth as broken in 1.3.29 (#585) --- src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json b/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json index 1e9d2e49..1072aa1d 100644 --- a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json +++ b/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json @@ -733,6 +733,11 @@ "Default | UpdateKey": "Nexus:985" }, + "Grass Growth": { + "ID": "bcmpinc.GrassGrowth", + "~0.3 | Status": "AssumeBroken" // broke in 1.3.29 (runtime errors: System.IndexOutOfRangeException: Could not find instruction sequence) + }, + "Happy Animals": { "ID": "HappyAnimals", "~1.0.3 | Status": "AssumeBroken" // broke in SMAPI 2.0 -- cgit From cd83782ef982b9791b233e384170e0064564c041 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 24 Aug 2018 20:35:13 -0400 Subject: fetch mod update keys from wiki when available --- docs/release-notes.md | 1 + src/SMAPI.Web/Controllers/ModsApiController.cs | 53 ++++++++++++++++------ .../Framework/ModData/ModDataRecord.cs | 9 ++++ 3 files changed, 49 insertions(+), 14 deletions(-) (limited to 'src/SMAPI.Web') diff --git a/docs/release-notes.md b/docs/release-notes.md index 6af726a1..12feb68a 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -4,6 +4,7 @@ * Added support for subfolders under `Mods`, for players who want to organise their mods. * Moved most SMAPI files into a `smapi-internal` subfolder. * Moved save backups into a `save-backups` subfolder (instead of `Mods/SaveBackup/backups`). Note that previous backups will be deleted when you update. + * Update checks now work even when the mod has no update keys in most cases. * Fixed installer duplicating bundled mods if you moved them after the last install. * Fixed crash when a mod manifest is corrupted. * Fixed error-handling when initialising paths. diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs index 18d55665..3d05da16 100644 --- a/src/SMAPI.Web/Controllers/ModsApiController.cs +++ b/src/SMAPI.Web/Controllers/ModsApiController.cs @@ -115,15 +115,10 @@ namespace StardewModdingAPI.Web.Controllers /// Returns the mod data if found, else null. private async Task GetModData(ModSearchEntryModel search, WikiCompatibilityEntry[] wikiData, bool includeExtendedMetadata) { - // resolve update keys - var updateKeys = new HashSet(search.UpdateKeys ?? new string[0], StringComparer.InvariantCultureIgnoreCase); + // crossreference data ModDataRecord record = this.ModDatabase.Get(search.ID); - if (record?.Fields != null) - { - string defaultUpdateKey = record.Fields.FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey && p.IsDefault)?.Value; - if (!string.IsNullOrWhiteSpace(defaultUpdateKey)) - updateKeys.Add(defaultUpdateKey); - } + WikiCompatibilityEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.InvariantCultureIgnoreCase)); + string[] updateKeys = this.GetUpdateKeys(search.UpdateKeys, record, wikiEntry).ToArray(); // get latest versions ModEntryModel result = new ModEntryModel { ID = search.ID }; @@ -166,7 +161,6 @@ namespace StardewModdingAPI.Web.Controllers } // get unofficial version - WikiCompatibilityEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(result.ID.Trim(), StringComparer.InvariantCultureIgnoreCase)); if (wikiEntry?.UnofficialVersion != null && this.IsNewer(wikiEntry.UnofficialVersion, result.Main?.Version) && this.IsNewer(wikiEntry.UnofficialVersion, result.Optional?.Version)) result.Unofficial = new ModEntryVersionModel(wikiEntry.UnofficialVersion, this.WikiCompatibilityPageUrl); @@ -229,7 +223,7 @@ namespace StardewModdingAPI.Web.Controllers private async Task GetWikiDataAsync() { ModToolkit toolkit = new ModToolkit(); - return await this.Cache.GetOrCreateAsync($"_wiki", async entry => + return await this.Cache.GetOrCreateAsync("_wiki", async entry => { try { @@ -273,11 +267,42 @@ namespace StardewModdingAPI.Web.Controllers }); } - /// Get the requested API version. - private ISemanticVersion GetApiVersion() + /// Get update keys based on the available mod metadata, while maintaining the precedence order. + /// The specified update keys. + /// The mod's entry in SMAPI's internal database. + /// The mod's entry in the wiki list. + public IEnumerable GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiCompatibilityEntry entry) { - string actualVersion = (string)this.RouteData.Values["version"]; - return new SemanticVersion(actualVersion); + IEnumerable GetRaw() + { + // specified update keys + if (specifiedKeys != null) + { + foreach (string key in specifiedKeys) + yield return key?.Trim(); + } + + // default update key + string defaultKey = record?.GetDefaultUpdateKey(); + if (defaultKey != null) + yield return defaultKey; + + // wiki metadata + if (entry != null) + { + if (entry.NexusID.HasValue) + yield return $"Nexus:{entry.NexusID}"; + if (entry.ChucklefishID.HasValue) + yield return $"Chucklefish:{entry.ChucklefishID}"; + } + } + + HashSet seen = new HashSet(StringComparer.InvariantCulture); + foreach (string key in GetRaw()) + { + if (!string.IsNullOrWhiteSpace(key) && seen.Add(key)) + yield return key; + } } } } diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs index 82ac8837..3949f7dc 100644 --- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs +++ b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs @@ -96,6 +96,15 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData .Distinct(); } + /// Get the default update key for this mod, if any. + public string GetDefaultUpdateKey() + { + string updateKey = this.Fields.FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey && p.IsDefault)?.Value; + return !string.IsNullOrWhiteSpace(updateKey) + ? updateKey + : null; + } + /// Get a parsed representation of the which match a given manifest. /// The manifest to match. public ModDataRecordVersionedFields GetVersionedFields(IManifest manifest) -- cgit From da29f3f08f2192cdce2d3a9ed3c55680421e0caf Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 26 Aug 2018 12:25:25 -0400 Subject: make beta download blurb configurable (#585) --- src/SMAPI.Web/Controllers/IndexController.cs | 4 ++-- src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs | 5 ++++- src/SMAPI.Web/ViewModels/IndexModel.cs | 7 ++++++- src/SMAPI.Web/Views/Index/Index.cshtml | 8 +++++++- src/SMAPI.Web/appsettings.Development.json | 3 ++- src/SMAPI.Web/appsettings.json | 3 ++- 6 files changed, 23 insertions(+), 7 deletions(-) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/Controllers/IndexController.cs b/src/SMAPI.Web/Controllers/IndexController.cs index 8c4a0332..dadbedd1 100644 --- a/src/SMAPI.Web/Controllers/IndexController.cs +++ b/src/SMAPI.Web/Controllers/IndexController.cs @@ -67,12 +67,12 @@ namespace StardewModdingAPI.Web.Controllers IndexVersionModel stableVersionModel = stableVersion != null ? new IndexVersionModel(stableVersion.Version.ToString(), stableVersion.Release.Body, stableVersion.Asset.DownloadUrl, stableVersionForDevs?.Asset.DownloadUrl) : new IndexVersionModel("unknown", "", "https://github.com/Pathoschild/SMAPI/releases", null); // just in case something goes wrong) - IndexVersionModel betaVersionModel = betaVersion != null && this.SiteConfig.EnableSmapiBeta + IndexVersionModel betaVersionModel = betaVersion != null && this.SiteConfig.BetaEnabled ? new IndexVersionModel(betaVersion.Version.ToString(), betaVersion.Release.Body, betaVersion.Asset.DownloadUrl, betaVersionForDevs?.Asset.DownloadUrl) : null; // render view - var model = new IndexModel(stableVersionModel, betaVersionModel); + var model = new IndexModel(stableVersionModel, betaVersionModel, this.SiteConfig.BetaBlurb); return this.View(model); } diff --git a/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs b/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs index 3d428015..c0e4c4c8 100644 --- a/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs +++ b/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs @@ -13,6 +13,9 @@ namespace StardewModdingAPI.Web.Framework.ConfigModels public string LogParserUrl { get; set; } /// Whether to show SMAPI beta versions on the main page, if any. - public bool EnableSmapiBeta { get; set; } + public bool BetaEnabled { get; set; } + + /// A short sentence shown under the beta download button, if any. + public string BetaBlurb { get; set; } } } diff --git a/src/SMAPI.Web/ViewModels/IndexModel.cs b/src/SMAPI.Web/ViewModels/IndexModel.cs index 4268c878..82c4e06f 100644 --- a/src/SMAPI.Web/ViewModels/IndexModel.cs +++ b/src/SMAPI.Web/ViewModels/IndexModel.cs @@ -12,6 +12,9 @@ namespace StardewModdingAPI.Web.ViewModels /// The latest prerelease SMAPI version (if newer than ). public IndexVersionModel BetaVersion { get; set; } + /// A short sentence shown under the beta download button, if any. + public string BetaBlurb { get; set; } + /********* ** Public methods @@ -22,10 +25,12 @@ namespace StardewModdingAPI.Web.ViewModels /// Construct an instance. /// The latest stable SMAPI version. /// The latest prerelease SMAPI version (if newer than ). - internal IndexModel(IndexVersionModel stableVersion, IndexVersionModel betaVersion) + /// A short sentence shown under the beta download button, if any. + internal IndexModel(IndexVersionModel stableVersion, IndexVersionModel betaVersion, string betaBlurb) { this.StableVersion = stableVersion; this.BetaVersion = betaVersion; + this.BetaBlurb = betaBlurb; } } } diff --git a/src/SMAPI.Web/Views/Index/Index.cshtml b/src/SMAPI.Web/Views/Index/Index.cshtml index 361d01de..ce0e6275 100644 --- a/src/SMAPI.Web/Views/Index/Index.cshtml +++ b/src/SMAPI.Web/Views/Index/Index.cshtml @@ -26,7 +26,13 @@ @if (Model.BetaVersion != null) {
- Download SMAPI @Model.BetaVersion.Version
for Stardew Valley 1.3 beta

+ + Download SMAPI @Model.BetaVersion.Version + @if (!string.IsNullOrWhiteSpace(Model.BetaBlurb)) + { +
@Model.BetaBlurb + } +

} - @mod.Author + + @mod.Author + @if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out contentPackList)) + { +
+ @foreach (var contentPack in contentPackList) + { + + @contentPack.Author
+ } +
+ } + @if (mod.Errors == 0) { no errors -- cgit From 5a9c9360d445254ef8290fc0f5fd48117f07a2b0 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 11 Oct 2018 18:34:04 -0400 Subject: update supporter list --- src/SMAPI.Web/Views/Index/Index.cshtml | 1 + 1 file changed, 1 insertion(+) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/Views/Index/Index.cshtml b/src/SMAPI.Web/Views/Index/Index.cshtml index 8f82005e..6eb82e64 100644 --- a/src/SMAPI.Web/Views/Index/Index.cshtml +++ b/src/SMAPI.Web/Views/Index/Index.cshtml @@ -99,6 +99,7 @@ else cheesysteak, hawkfalcon, jwdred, + Karmylla, Pucklynn, Robby LaFarge, and a few anonymous users for their ongoing support; you're awesome! 🏅 -- cgit From f09befe24047de8187276c722557b6f0fddd6e35 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 20 Oct 2018 14:55:13 -0400 Subject: expand metadata fetched from the wiki (#597) --- src/SMAPI.Web/Controllers/ModsApiController.cs | 26 ++--- .../Clients/WebApi/ModExtendedMetadataModel.cs | 10 +- .../Clients/Wiki/WikiCompatibilityClient.cs | 123 ++++++++++++--------- .../Clients/Wiki/WikiCompatibilityEntry.cs | 60 ---------- .../Clients/Wiki/WikiCompatibilityInfo.cs | 21 ++++ .../Framework/Clients/Wiki/WikiModEntry.cs | 54 +++++++++ src/StardewModdingAPI.Toolkit/ModToolkit.cs | 2 +- 7 files changed, 162 insertions(+), 134 deletions(-) delete mode 100644 src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityEntry.cs create mode 100644 src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityInfo.cs create mode 100644 src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs index 592c8f97..5caa5758 100644 --- a/src/SMAPI.Web/Controllers/ModsApiController.cs +++ b/src/SMAPI.Web/Controllers/ModsApiController.cs @@ -90,7 +90,7 @@ namespace StardewModdingAPI.Web.Controllers return new ModEntryModel[0]; // fetch wiki data - WikiCompatibilityEntry[] wikiData = await this.GetWikiDataAsync(); + WikiModEntry[] wikiData = await this.GetWikiDataAsync(); IDictionary mods = new Dictionary(StringComparer.CurrentCultureIgnoreCase); foreach (ModSearchEntryModel mod in model.Mods) { @@ -114,11 +114,11 @@ namespace StardewModdingAPI.Web.Controllers /// The wiki data. /// Whether to include extended metadata for each mod. /// Returns the mod data if found, else null. - private async Task GetModData(ModSearchEntryModel search, WikiCompatibilityEntry[] wikiData, bool includeExtendedMetadata) + private async Task GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata) { // crossreference data ModDataRecord record = this.ModDatabase.Get(search.ID); - WikiCompatibilityEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.InvariantCultureIgnoreCase)); + WikiModEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.InvariantCultureIgnoreCase)); string[] updateKeys = this.GetUpdateKeys(search.UpdateKeys, record, wikiEntry).ToArray(); // get latest versions @@ -162,19 +162,19 @@ namespace StardewModdingAPI.Web.Controllers } // get unofficial version - if (wikiEntry?.UnofficialVersion != null && this.IsNewer(wikiEntry.UnofficialVersion, result.Main?.Version) && this.IsNewer(wikiEntry.UnofficialVersion, result.Optional?.Version)) - result.Unofficial = new ModEntryVersionModel(wikiEntry.UnofficialVersion, this.WikiCompatibilityPageUrl); + if (wikiEntry?.Compatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, result.Main?.Version) && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, result.Optional?.Version)) + result.Unofficial = new ModEntryVersionModel(wikiEntry.Compatibility.UnofficialVersion, this.WikiCompatibilityPageUrl); // get unofficial version for beta if (wikiEntry?.HasBetaInfo == true) { result.HasBetaInfo = true; - if (wikiEntry.BetaStatus == WikiCompatibilityStatus.Unofficial) + if (wikiEntry.BetaCompatibility.Status == WikiCompatibilityStatus.Unofficial) { - if (wikiEntry.BetaUnofficialVersion != null) + if (wikiEntry.BetaCompatibility.UnofficialVersion != null) { - result.UnofficialForBeta = (wikiEntry.BetaUnofficialVersion != null && this.IsNewer(wikiEntry.BetaUnofficialVersion, result.Main?.Version) && this.IsNewer(wikiEntry.BetaUnofficialVersion, result.Optional?.Version)) - ? new ModEntryVersionModel(wikiEntry.BetaUnofficialVersion, this.WikiCompatibilityPageUrl) + result.UnofficialForBeta = (wikiEntry.BetaCompatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, result.Main?.Version) && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, result.Optional?.Version)) + ? new ModEntryVersionModel(wikiEntry.BetaCompatibility.UnofficialVersion, this.WikiCompatibilityPageUrl) : null; } else @@ -216,21 +216,21 @@ namespace StardewModdingAPI.Web.Controllers } /// Get mod data from the wiki compatibility list. - private async Task GetWikiDataAsync() + private async Task GetWikiDataAsync() { ModToolkit toolkit = new ModToolkit(); return await this.Cache.GetOrCreateAsync("_wiki", async entry => { try { - WikiCompatibilityEntry[] entries = await toolkit.GetWikiCompatibilityListAsync(); + WikiModEntry[] entries = await toolkit.GetWikiCompatibilityListAsync(); entry.AbsoluteExpiration = DateTimeOffset.UtcNow.AddMinutes(this.SuccessCacheMinutes); return entries; } catch { entry.AbsoluteExpiration = DateTimeOffset.UtcNow.AddMinutes(this.ErrorCacheMinutes); - return new WikiCompatibilityEntry[0]; + return new WikiModEntry[0]; } }); } @@ -268,7 +268,7 @@ namespace StardewModdingAPI.Web.Controllers /// The specified update keys. /// The mod's entry in SMAPI's internal database. /// The mod's entry in the wiki list. - public IEnumerable GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiCompatibilityEntry entry) + public IEnumerable GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry) { IEnumerable GetRaw() { diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs index 0f3cb26f..e6f2e4b4 100644 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs +++ b/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs @@ -68,7 +68,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// Construct an instance. /// The mod metadata from the wiki (if available). /// The mod metadata from SMAPI's internal DB (if available). - public ModExtendedMetadataModel(WikiCompatibilityEntry wiki, ModDataRecord db) + public ModExtendedMetadataModel(WikiModEntry wiki, ModDataRecord db) { // wiki data if (wiki != null) @@ -81,11 +81,11 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi this.CustomSourceUrl = wiki.CustomSourceUrl; this.CustomUrl = wiki.CustomUrl; - this.CompatibilityStatus = wiki.Status; - this.CompatibilitySummary = wiki.Summary; + this.CompatibilityStatus = wiki.Compatibility.Status; + this.CompatibilitySummary = wiki.Compatibility.Summary; - this.BetaCompatibilityStatus = wiki.BetaStatus; - this.BetaCompatibilitySummary = wiki.BetaSummary; + this.BetaCompatibilityStatus = wiki.BetaCompatibility?.Status; + this.BetaCompatibilitySummary = wiki.BetaCompatibility?.Summary; } // internal DB data diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityClient.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityClient.cs index 4060ed36..569e820b 100644 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityClient.cs +++ b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityClient.cs @@ -30,7 +30,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki } /// Fetch mod compatibility entries. - public async Task FetchAsync() + public async Task FetchAsync() { // fetch HTML ResponseModel response = await this.Client @@ -69,100 +69,113 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki *********/ /// Parse valid mod compatibility entries. /// The HTML compatibility entries. - private IEnumerable ParseEntries(IEnumerable nodes) + private IEnumerable ParseEntries(IEnumerable nodes) { foreach (HtmlNode node in nodes) { - // parse mod info - string name = node.Descendants("td").FirstOrDefault()?.Descendants("a")?.FirstOrDefault()?.InnerText?.Trim(); - string[] ids = this.GetAttribute(node, "data-id")?.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()).ToArray() ?? new string[0]; - int? nexusID = this.GetNullableIntAttribute(node, "data-nexus-id"); - int? chucklefishID = this.GetNullableIntAttribute(node, "data-chucklefish-id"); - string githubRepo = this.GetAttribute(node, "data-github"); - string customSourceUrl = this.GetAttribute(node, "data-custom-source"); - string customUrl = this.GetAttribute(node, "data-custom-url"); + // extract fields + string name = this.GetMetadataField(node, "mod-name"); + string alternateNames = this.GetMetadataField(node, "mod-name2"); + string author = this.GetMetadataField(node, "mod-author"); + string alternateAuthors = this.GetMetadataField(node, "mod-author2"); + string[] ids = this.GetMetadataField(node, "mod-id")?.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()).ToArray() ?? new string[0]; + int? nexusID = this.GetNullableIntField(node, "mod-nexus-id"); + int? chucklefishID = this.GetNullableIntField(node, "mod-chucklefish-id"); + string githubRepo = this.GetMetadataField(node, "mod-github"); + string customSourceUrl = this.GetMetadataField(node, "mod-custom-source"); + string customUrl = this.GetMetadataField(node, "mod-url"); + string brokeIn = this.GetMetadataField(node, "mod-broke-in"); + string anchor = this.GetMetadataField(node, "mod-anchor"); // parse stable compatibility - WikiCompatibilityStatus status = this.GetStatusAttribute(node, "data-status") ?? WikiCompatibilityStatus.Ok; - ISemanticVersion unofficialVersion = this.GetSemanticVersionAttribute(node, "data-unofficial-version"); - string summary = node.Descendants().FirstOrDefault(p => p.HasClass("data-summary"))?.InnerText.Trim(); + WikiCompatibilityInfo compatibility = new WikiCompatibilityInfo + { + Status = this.GetStatusField(node, "mod-status") ?? WikiCompatibilityStatus.Ok, + UnofficialVersion = this.GetSemanticVersionField(node, "mod-unofficial-version"), + UnofficialUrl = this.GetMetadataField(node, "mod-unofficial-url"), + Summary = this.GetMetadataField(node, "mod-summary")?.Trim() + }; // parse beta compatibility - WikiCompatibilityStatus? betaStatus = this.GetStatusAttribute(node, "data-beta-status"); - ISemanticVersion betaUnofficialVersion = betaStatus.HasValue ? this.GetSemanticVersionAttribute(node, "data-beta-unofficial-version") : null; - string betaSummary = betaStatus.HasValue ? node.Descendants().FirstOrDefault(p => p.HasClass("data-beta-summary"))?.InnerText.Trim() : null; + WikiCompatibilityInfo betaCompatibility = null; + { + WikiCompatibilityStatus? betaStatus = this.GetStatusField(node, "mod-beta-status"); + if (betaStatus.HasValue) + { + betaCompatibility = new WikiCompatibilityInfo + { + Status = betaStatus.Value, + UnofficialVersion = this.GetSemanticVersionField(node, "mod-beta-unofficial-version"), + UnofficialUrl = this.GetMetadataField(node, "mod-beta-unofficial-url"), + Summary = this.GetMetadataField(node, "mod-beta-summary") + }; + } + } // yield model - yield return new WikiCompatibilityEntry + yield return new WikiModEntry { - // mod info ID = ids, Name = name, + AlternateNames = alternateNames, + Author = author, + AlternateAuthors = alternateAuthors, NexusID = nexusID, ChucklefishID = chucklefishID, GitHubRepo = githubRepo, CustomSourceUrl = customSourceUrl, CustomUrl = customUrl, - - // stable compatibility - Status = status, - Summary = summary, - UnofficialVersion = unofficialVersion, - - // beta compatibility - BetaStatus = betaStatus, - BetaSummary = betaSummary, - BetaUnofficialVersion = betaUnofficialVersion + BrokeIn = brokeIn, + Compatibility = compatibility, + BetaCompatibility = betaCompatibility, + Anchor = anchor }; } } - /// Get a compatibility status attribute value. - /// The HTML node. - /// The attribute name. - private WikiCompatibilityStatus? GetStatusAttribute(HtmlNode node, string attributeName) + /// Get the value of a metadata field. + /// The metadata container. + /// The field name. + private string GetMetadataField(HtmlNode container, string name) { - string raw = node.GetAttributeValue(attributeName, null); + return container.Descendants().FirstOrDefault(p => p.HasClass(name))?.InnerHtml; + } + + /// Get the value of a metadata field as a compatibility status. + /// The metadata container. + /// The field name. + private WikiCompatibilityStatus? GetStatusField(HtmlNode container, string name) + { + string raw = this.GetMetadataField(container, name); if (raw == null) - return null; // not a mod node? + return null; if (!Enum.TryParse(raw, true, out WikiCompatibilityStatus status)) throw new InvalidOperationException($"Unknown status '{raw}' when parsing compatibility list."); return status; } - /// Get a semantic version attribute value. - /// The HTML node. - /// The attribute name. - private ISemanticVersion GetSemanticVersionAttribute(HtmlNode node, string attributeName) + /// Get the value of a metadata field as a semantic version. + /// The metadata container. + /// The field name. + private ISemanticVersion GetSemanticVersionField(HtmlNode container, string name) { - string raw = node.GetAttributeValue(attributeName, null); + string raw = this.GetMetadataField(container, name); return SemanticVersion.TryParse(raw, out ISemanticVersion version) ? version : null; } - /// Get a nullable integer attribute value. - /// The HTML node. - /// The attribute name. - private int? GetNullableIntAttribute(HtmlNode node, string attributeName) + /// Get the value of a metadata field as a nullable integer. + /// The metadata container. + /// The field name. + private int? GetNullableIntField(HtmlNode container, string name) { - string raw = this.GetAttribute(node, attributeName); + string raw = this.GetMetadataField(container, name); if (raw != null && int.TryParse(raw, out int value)) return value; return null; } - /// Get a strings attribute value. - /// The HTML node. - /// The attribute name. - private string GetAttribute(HtmlNode node, string attributeName) - { - string raw = node.GetAttributeValue(attributeName, null); - if (raw != null) - raw = HtmlEntity.DeEntitize(raw); - return raw; - } - /// The response model for the MediaWiki parse API. [SuppressMessage("ReSharper", "ClassNeverInstantiated.Local")] [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")] diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityEntry.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityEntry.cs deleted file mode 100644 index 3cb9c97c..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityEntry.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki -{ - /// An entry in the mod compatibility list. - public class WikiCompatibilityEntry - { - /********* - ** Accessors - *********/ - /**** - ** Mod info - ****/ - /// The mod's unique ID. A mod may have multiple current IDs in rare cases (e.g. due to parallel releases or unofficial updates). - public string[] ID { get; set; } - - /// The mod's display name. - public string Name { get; set; } - - /// The mod ID on Nexus. - public int? NexusID { get; set; } - - /// The mod ID in the Chucklefish mod repo. - public int? ChucklefishID { get; set; } - - /// The GitHub repository in the form 'owner/repo'. - public string GitHubRepo { get; set; } - - /// The URL to a non-GitHub source repo. - public string CustomSourceUrl { get; set; } - - /// The custom mod page URL (if applicable). - public string CustomUrl { get; set; } - - /**** - ** Stable compatibility - ****/ - /// The compatibility status. - public WikiCompatibilityStatus Status { get; set; } - - /// The human-readable summary of the compatibility status or workaround, without HTML formatting. - public string Summary { get; set; } - - /// The version of the latest unofficial update, if applicable. - public ISemanticVersion UnofficialVersion { get; set; } - - /**** - ** Beta compatibility - ****/ - /// Whether a Stardew Valley or SMAPI beta which affects mod compatibility is in progress. If this is true, should be used for beta versions of SMAPI instead of . - public bool HasBetaInfo => this.BetaStatus != null; - - /// The compatibility status for the Stardew Valley beta, if a beta is in progress. - public WikiCompatibilityStatus? BetaStatus { get; set; } - - /// The human-readable summary of the compatibility status or workaround for the Stardew Valley beta (if any), without HTML formatting. - public string BetaSummary { get; set; } - - /// The version of the latest unofficial update for the Stardew Valley beta (if any), if applicable. - public ISemanticVersion BetaUnofficialVersion { get; set; } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityInfo.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityInfo.cs new file mode 100644 index 00000000..2725df1a --- /dev/null +++ b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityInfo.cs @@ -0,0 +1,21 @@ +namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki +{ + /// Compatibility info for a mod. + public class WikiCompatibilityInfo + { + /********* + ** Accessors + *********/ + /// The compatibility status. + public WikiCompatibilityStatus Status { get; set; } + + /// The human-readable summary of the compatibility status or workaround, without HTML formatting. + public string Summary { get; set; } + + /// The version of the latest unofficial update, if applicable. + public ISemanticVersion UnofficialVersion { get; set; } + + /// The URL to the latest unofficial update, if applicable. + public string UnofficialUrl { get; set; } + } +} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs new file mode 100644 index 00000000..752b526c --- /dev/null +++ b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs @@ -0,0 +1,54 @@ +namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki +{ + /// A mod entry in the wiki list. + public class WikiModEntry + { + /********* + ** Accessors + *********/ + /// The mod's unique ID. A mod may have multiple current IDs in rare cases (e.g. due to parallel releases or unofficial updates). + public string[] ID { get; set; } + + /// The mod's display name. + public string Name { get; set; } + + /// The mod's alternative names, if any. + public string AlternateNames { get; set; } + + /// The mod's author name. + public string Author { get; set; } + + /// The mod's alternative author names, if any. + public string AlternateAuthors { get; set; } + + /// The mod ID on Nexus. + public int? NexusID { get; set; } + + /// The mod ID in the Chucklefish mod repo. + public int? ChucklefishID { get; set; } + + /// The GitHub repository in the form 'owner/repo'. + public string GitHubRepo { get; set; } + + /// The URL to a non-GitHub source repo. + public string CustomSourceUrl { get; set; } + + /// The custom mod page URL (if applicable). + public string CustomUrl { get; set; } + + /// The game or SMAPI version which broke this mod (if applicable). + public string BrokeIn { get; set; } + + /// The mod's compatibility with the latest stable version of the game. + public WikiCompatibilityInfo Compatibility { get; set; } + + /// The mod's compatibility with the latest beta version of the game (if any). + public WikiCompatibilityInfo BetaCompatibility { get; set; } + + /// Whether a Stardew Valley or SMAPI beta which affects mod compatibility is in progress. If this is true, should be used for beta versions of SMAPI instead of . + public bool HasBetaInfo => this.BetaCompatibility != null; + + /// The link anchor for the mod entry in the wiki compatibility list. + public string Anchor { get; set; } + } +} diff --git a/src/StardewModdingAPI.Toolkit/ModToolkit.cs b/src/StardewModdingAPI.Toolkit/ModToolkit.cs index 8c78b2f3..44503b20 100644 --- a/src/StardewModdingAPI.Toolkit/ModToolkit.cs +++ b/src/StardewModdingAPI.Toolkit/ModToolkit.cs @@ -47,7 +47,7 @@ namespace StardewModdingAPI.Toolkit } /// Extract mod metadata from the wiki compatibility list. - public async Task GetWikiCompatibilityListAsync() + public async Task GetWikiCompatibilityListAsync() { var client = new WikiCompatibilityClient(this.UserAgent); return await client.FetchAsync(); -- cgit From 28fdb9e4e7f5419947226171bf6d7efa273802c5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 20 Oct 2018 15:10:44 -0400 Subject: add mod compatibility page (#597) --- src/SMAPI.Web/Controllers/ModsController.cs | 33 +++++++ src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs | 3 + src/SMAPI.Web/StardewModdingAPI.Web.csproj | 3 + src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs | 34 +++++++ src/SMAPI.Web/ViewModels/ModLinkModel.cs | 28 ++++++ src/SMAPI.Web/ViewModels/ModListModel.cs | 36 +++++++ src/SMAPI.Web/ViewModels/ModModel.cs | 107 +++++++++++++++++++++ src/SMAPI.Web/Views/Mods/Index.cshtml | 72 ++++++++++++++ src/SMAPI.Web/Views/Shared/_Layout.cshtml | 1 + src/SMAPI.Web/appsettings.Development.json | 1 + src/SMAPI.Web/appsettings.json | 1 + src/SMAPI.Web/wwwroot/Content/css/mods.css | 85 ++++++++++++++++ src/SMAPI.Web/wwwroot/Content/js/mods.js | 56 +++++++++++ 13 files changed, 460 insertions(+) create mode 100644 src/SMAPI.Web/Controllers/ModsController.cs create mode 100644 src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs create mode 100644 src/SMAPI.Web/ViewModels/ModLinkModel.cs create mode 100644 src/SMAPI.Web/ViewModels/ModListModel.cs create mode 100644 src/SMAPI.Web/ViewModels/ModModel.cs create mode 100644 src/SMAPI.Web/Views/Mods/Index.cshtml create mode 100644 src/SMAPI.Web/wwwroot/Content/css/mods.css create mode 100644 src/SMAPI.Web/wwwroot/Content/js/mods.js (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/Controllers/ModsController.cs b/src/SMAPI.Web/Controllers/ModsController.cs new file mode 100644 index 00000000..99d19f76 --- /dev/null +++ b/src/SMAPI.Web/Controllers/ModsController.cs @@ -0,0 +1,33 @@ +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using StardewModdingAPI.Toolkit; +using StardewModdingAPI.Toolkit.Framework.Clients.Wiki; +using StardewModdingAPI.Web.ViewModels; + +namespace StardewModdingAPI.Web.Controllers +{ + /// Provides user-friendly info about SMAPI mods. + internal class ModsController : Controller + { + /********* + ** Public methods + *********/ + /// Display information for all mods. + [HttpGet] + [Route("mods")] + public async Task Index() + { + WikiModEntry[] mods = await new ModToolkit().GetWikiCompatibilityListAsync(); + ModListModel viewModel = new ModListModel( + stableVersion: "1.3.28", + betaVersion: "1.3.31-beta", + mods: mods + .Select(mod => new ModModel(mod)) + .OrderBy(p => Regex.Replace(p.Name.ToLower(), "[^a-z0-9]", "")) // ignore case, spaces, and special characters when sorting + ); + return this.View("Index", viewModel); + } + } +} diff --git a/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs b/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs index c0e4c4c8..d89a4260 100644 --- a/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs +++ b/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs @@ -12,6 +12,9 @@ namespace StardewModdingAPI.Web.Framework.ConfigModels /// The root URL for the log parser. public string LogParserUrl { get; set; } + /// The root URL for the mod list. + public string ModListUrl { get; set; } + /// Whether to show SMAPI beta versions on the main page, if any. public bool BetaEnabled { get; set; } diff --git a/src/SMAPI.Web/StardewModdingAPI.Web.csproj b/src/SMAPI.Web/StardewModdingAPI.Web.csproj index dc87cc98..4814d169 100644 --- a/src/SMAPI.Web/StardewModdingAPI.Web.csproj +++ b/src/SMAPI.Web/StardewModdingAPI.Web.csproj @@ -27,6 +27,9 @@ + + $(IncludeRazorContentInPack) + PreserveNewest diff --git a/src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs b/src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs new file mode 100644 index 00000000..d331c093 --- /dev/null +++ b/src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs @@ -0,0 +1,34 @@ +using StardewModdingAPI.Toolkit.Framework.Clients.Wiki; + +namespace StardewModdingAPI.Web.ViewModels +{ + /// Metadata about a mod's compatibility with the latest versions of SMAPI and Stardew Valley. + public class ModCompatibilityModel + { + /********* + ** Accessors + *********/ + /// The compatibility status, as a string like "Broken". + public string Status { get; set; } + + /// A link to the unofficial version which fixes compatibility, if any. + public ModLinkModel UnofficialVersion { get; set; } + + /// The human-readable summary, as an HTML block. + public string Summary { get; set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The mod metadata. + public ModCompatibilityModel(WikiCompatibilityInfo info) + { + this.Status = info.Status.ToString(); + if (info.UnofficialVersion != null) + this.UnofficialVersion = new ModLinkModel(info.UnofficialUrl, info.UnofficialVersion.ToString()); + this.Summary = info.Summary; + } + } +} diff --git a/src/SMAPI.Web/ViewModels/ModLinkModel.cs b/src/SMAPI.Web/ViewModels/ModLinkModel.cs new file mode 100644 index 00000000..97dd215c --- /dev/null +++ b/src/SMAPI.Web/ViewModels/ModLinkModel.cs @@ -0,0 +1,28 @@ +namespace StardewModdingAPI.Web.ViewModels +{ + /// Metadata about a link. + public class ModLinkModel + { + /********* + ** Accessors + *********/ + /// The URL of the linked page. + public string Url { get; set; } + + /// The suggested link text. + public string Text { get; set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The URL of the linked page. + /// The suggested link text. + public ModLinkModel(string url, string text) + { + this.Url = url; + this.Text = text; + } + } +} diff --git a/src/SMAPI.Web/ViewModels/ModListModel.cs b/src/SMAPI.Web/ViewModels/ModListModel.cs new file mode 100644 index 00000000..3b87d393 --- /dev/null +++ b/src/SMAPI.Web/ViewModels/ModListModel.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Linq; + +namespace StardewModdingAPI.Web.ViewModels +{ + /// Metadata for the mod list page. + public class ModListModel + { + /********* + ** Accessors + *********/ + /// The current stable version of the game. + public string StableVersion { get; set; } + + /// The current beta version of the game (if any). + public string BetaVersion { get; set; } + + /// The mods to display. + public ModModel[] Mods { get; set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The current stable version of the game. + /// The current beta version of the game (if any). + /// The mods to display. + public ModListModel(string stableVersion, string betaVersion, IEnumerable mods) + { + this.StableVersion = stableVersion; + this.BetaVersion = betaVersion; + this.Mods = mods.ToArray(); + } + } +} diff --git a/src/SMAPI.Web/ViewModels/ModModel.cs b/src/SMAPI.Web/ViewModels/ModModel.cs new file mode 100644 index 00000000..4fb9d5b5 --- /dev/null +++ b/src/SMAPI.Web/ViewModels/ModModel.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using System.Linq; +using StardewModdingAPI.Toolkit.Framework.Clients.Wiki; + +namespace StardewModdingAPI.Web.ViewModels +{ + /// Metadata about a mod. + public class ModModel + { + /********* + ** Accessors + *********/ + /// The mod name. + public string Name { get; set; } + + /// The mod's alternative names, if any. + public string AlternateNames { get; set; } + + /// The mod author's name. + public string Author { get; set; } + + /// The mod author's alternative names, if any. + public string AlternateAuthors { get; set; } + + /// The URL to the mod's source code, if any. + public string SourceUrl { get; set; } + + /// The compatibility status for the stable version of the game. + public ModCompatibilityModel Compatibility { get; set; } + + /// The compatibility status for the beta version of the game. + public ModCompatibilityModel BetaCompatibility { get; set; } + + /// Links to the available mod pages. + public ModLinkModel[] ModPages { get; set; } + + /// The game or SMAPI version which broke this mod (if applicable). + public string BrokeIn { get; set; } + + /// A unique identifier for the mod that can be used in an anchor URL. + public string Slug { get; set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The mod metadata. + public ModModel(WikiModEntry entry) + { + // basic info + this.Name = entry.Name; + this.AlternateNames = entry.AlternateNames; + this.Author = entry.Author; + this.AlternateAuthors = entry.AlternateAuthors; + this.SourceUrl = this.GetSourceUrl(entry); + this.Compatibility = new ModCompatibilityModel(entry.Compatibility); + this.BetaCompatibility = entry.BetaCompatibility != null ? new ModCompatibilityModel(entry.BetaCompatibility) : null; + this.ModPages = this.GetModPageUrls(entry).ToArray(); + this.BrokeIn = entry.BrokeIn; + this.Slug = entry.Anchor; + } + + + /********* + ** Private methods + *********/ + /// Get the web URL for the mod's source code repository, if any. + /// The mod metadata. + private string GetSourceUrl(WikiModEntry entry) + { + if (!string.IsNullOrWhiteSpace(entry.GitHubRepo)) + return $"https://github.com/{entry.GitHubRepo}"; + if (!string.IsNullOrWhiteSpace(entry.CustomSourceUrl)) + return entry.CustomSourceUrl; + return null; + } + + /// Get the web URLs for the mod pages, if any. + /// The mod metadata. + private IEnumerable GetModPageUrls(WikiModEntry entry) + { + bool anyFound = false; + + // normal mod pages + if (entry.NexusID.HasValue) + { + anyFound = true; + yield return new ModLinkModel($"https://www.nexusmods.com/stardewvalley/mods/{entry.NexusID}", "Nexus"); + } + if (entry.ChucklefishID.HasValue) + { + anyFound = true; + yield return new ModLinkModel($"https://community.playstarbound.com/resources/{entry.ChucklefishID}", "Chucklefish"); + } + + // fallback + if (!anyFound && !string.IsNullOrWhiteSpace(entry.CustomUrl)) + { + anyFound = true; + yield return new ModLinkModel(entry.CustomUrl, "custom"); + } + if (!anyFound && !string.IsNullOrWhiteSpace(entry.GitHubRepo)) + yield return new ModLinkModel($"https://github.com/{entry.GitHubRepo}/releases", "GitHub"); + } + } +} diff --git a/src/SMAPI.Web/Views/Mods/Index.cshtml b/src/SMAPI.Web/Views/Mods/Index.cshtml new file mode 100644 index 00000000..2b33fcaf --- /dev/null +++ b/src/SMAPI.Web/Views/Mods/Index.cshtml @@ -0,0 +1,72 @@ +@using Newtonsoft.Json +@model StardewModdingAPI.Web.ViewModels.ModListModel +@{ + ViewData["Title"] = "SMAPI mod compatibility"; +} +@section Head { + + + + + +} + +

This page lists all known SMAPI mods, whether they're compatible with the latest versions of Stardew Valley and SMAPI, and how to fix broken mods if possible. The list is updated every few days. (You can help edit this list!)

+ +@if (Model.BetaVersion != null) +{ +
+

Note: "SDV beta only" means Stardew Valley @Model.BetaVersion; if you didn't opt in to the beta, you have the stable version and can ignore that line. If a mod doesn't have a "SDV beta only" line, the compatibility applies to both versions of the game.

+
+} + +
+ + + + + + + + + + + + + + + + + + + + + +
mod namelinksauthorcompatibilitybroke incode 
+ {{mod.Name}} + (aka {{mod.AlternateNames}}) + + {{mod.Author}} + (aka {{mod.AlternateAuthors}}) + +
+
+ SDV beta only: + +
+
+ source + no source + + # +
+
diff --git a/src/SMAPI.Web/Views/Shared/_Layout.cshtml b/src/SMAPI.Web/Views/Shared/_Layout.cshtml index 29da9100..4c602b29 100644 --- a/src/SMAPI.Web/Views/Shared/_Layout.cshtml +++ b/src/SMAPI.Web/Views/Shared/_Layout.cshtml @@ -16,6 +16,7 @@

SMAPI

diff --git a/src/SMAPI.Web/appsettings.Development.json b/src/SMAPI.Web/appsettings.Development.json index dc22791b..db90a3de 100644 --- a/src/SMAPI.Web/appsettings.Development.json +++ b/src/SMAPI.Web/appsettings.Development.json @@ -19,6 +19,7 @@ "Site": { "RootUrl": "http://localhost:59482/", + "ModListUrl": "http://localhost:59482/mods/", "LogParserUrl": "http://localhost:59482/log/", "BetaEnabled": false, "BetaBlurb": null diff --git a/src/SMAPI.Web/appsettings.json b/src/SMAPI.Web/appsettings.json index 2c6aa0cc..401b885f 100644 --- a/src/SMAPI.Web/appsettings.json +++ b/src/SMAPI.Web/appsettings.json @@ -16,6 +16,7 @@ "Site": { "RootUrl": null, // see top note + "ModListUrl": null, // see top note "LogParserUrl": null, // see top note "BetaEnabled": null, // see top note "BetaBlurb": null // see top note diff --git a/src/SMAPI.Web/wwwroot/Content/css/mods.css b/src/SMAPI.Web/wwwroot/Content/css/mods.css new file mode 100644 index 00000000..d250440f --- /dev/null +++ b/src/SMAPI.Web/wwwroot/Content/css/mods.css @@ -0,0 +1,85 @@ +/********* +** Intro +*********/ +#content { + max-width: calc(100% - 2em); /* allow for wider table if room available */ +} + +#blurb { + margin-top: 0; + width: 50em; +} + +#beta-blurb { + width: 50em; + margin-bottom: 2em; + padding: 1em; + border: 3px solid darkgreen; +} + +table.wikitable { + background-color:#f8f9fa; + color:#222; + margin:1em 0; + border:1px solid #a2a9b1; + border-collapse:collapse +} + +table.wikitable > tr > th, +table.wikitable > tr > td, +table.wikitable > * > tr > th, +table.wikitable > * > tr > td { + border:1px solid #a2a9b1; + padding:0.2em 0.4em +} + +table.wikitable > tr > th, +table.wikitable > * > tr > th { + background-color:#eaecf0; +} + +table.wikitable > caption { + font-weight:bold +} + +#mod-list .mod-page-links, +#mod-list .mod-alt-authors, +#mod-list .mod-alt-names, +#mod-list .mod-broke-in { + font-size: 0.8em; +} + +#mod-list .mod-alt-authors, +#mod-list .mod-alt-names { + display: block; +} + +#mod-list tr { + font-size: 0.9em; +} + +#mod-list tr[data-status="Ok"], +#mod-list tr[data-status="Optional"] { + background: #9F9; +} + +#mod-list tr[data-status="Workaround"], +#mod-list tr[data-status="Unofficial"] { + background: #CF9; +} + +#mod-list tr[data-status="Broken"] { + background: #F99; +} + +#mod-list tr[data-status="Obsolete"], +#mod-list tr[data-status="Abandoned"] { + background: #999; + opacity: 0.7; +} + +#mod-list .mod-closed-source { + color: red; + font-size: 0.8em; + opacity: 0.5; +} diff --git a/src/SMAPI.Web/wwwroot/Content/js/mods.js b/src/SMAPI.Web/wwwroot/Content/js/mods.js new file mode 100644 index 00000000..1b15b622 --- /dev/null +++ b/src/SMAPI.Web/wwwroot/Content/js/mods.js @@ -0,0 +1,56 @@ +/* globals $ */ + +var smapi = smapi || {}; +var app; +smapi.modList = function (mods) { + // init data + var data = { mods: mods, search: "" }; + for (var i = 0; i < data.mods.length; i++) { + var mod = mods[i]; + + // set initial visibility + mod.Visible = true; + + // concatenate searchable text + mod.SearchableText = [mod.Name, mod.AlternateNames, mod.Author, mod.AlternateAuthors, mod.Compatibility.Summary, mod.BrokeIn]; + if (mod.Compatibility.UnofficialVersion) + mod.SearchableText.push(mod.Compatibility.UnofficialVersion); + if (mod.BetaCompatibility) { + mod.SearchableText.push(mod.BetaCompatibility.Summary); + if (mod.BetaCompatibility.UnofficialVersion) + mod.SearchableText.push(mod.BetaCompatibility.UnofficialVersion); + } + for (var p = 0; p < mod.ModPages; p++) + mod.SearchableField.push(mod.ModPages[p].Text); + mod.SearchableText = mod.SearchableText.join(" ").toLowerCase(); + } + + // init app + app = new Vue({ + el: "#app", + data: data, + methods: { + /** + * Update the visibility of all mods based on the current search text. + */ + applySearch: function () { + // get search terms + var words = data.search.toLowerCase().split(" "); + + // make sure all words match + for (var i = 0; i < data.mods.length; i++) { + var mod = data.mods[i]; + var match = true; + for (var w = 0; w < words.length; w++) { + if (mod.SearchableText.indexOf(words[w]) === -1) { + match = false; + break; + } + } + + mod.Visible = match; + } + } + } + }); +}; -- cgit From dff78fdf8f98a0f9581b56357107bb6680da62d8 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 20 Oct 2018 15:14:09 -0400 Subject: cache wiki data on mod compatibility page (#597) --- src/SMAPI.Web/Controllers/ModsController.cs | 58 ++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 9 deletions(-) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/Controllers/ModsController.cs b/src/SMAPI.Web/Controllers/ModsController.cs index 99d19f76..f258c745 100644 --- a/src/SMAPI.Web/Controllers/ModsController.cs +++ b/src/SMAPI.Web/Controllers/ModsController.cs @@ -1,9 +1,13 @@ +using System; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Options; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Toolkit.Framework.Clients.Wiki; +using StardewModdingAPI.Web.Framework.ConfigModels; using StardewModdingAPI.Web.ViewModels; namespace StardewModdingAPI.Web.Controllers @@ -11,23 +15,59 @@ namespace StardewModdingAPI.Web.Controllers /// Provides user-friendly info about SMAPI mods. internal class ModsController : Controller { + /********* + ** Properties + *********/ + /// The cache in which to store mod metadata. + private readonly IMemoryCache Cache; + + /// The number of minutes successful update checks should be cached before refetching them. + private readonly int SuccessCacheMinutes; + + /********* ** Public methods *********/ + /// Construct an instance. + /// The cache in which to store mod metadata. + /// The config settings for mod update checks. + public ModsController(IMemoryCache cache, IOptions configProvider) + { + ModUpdateCheckConfig config = configProvider.Value; + + this.Cache = cache; + this.SuccessCacheMinutes = config.SuccessCacheMinutes; + } + /// Display information for all mods. [HttpGet] [Route("mods")] public async Task Index() { - WikiModEntry[] mods = await new ModToolkit().GetWikiCompatibilityListAsync(); - ModListModel viewModel = new ModListModel( - stableVersion: "1.3.28", - betaVersion: "1.3.31-beta", - mods: mods - .Select(mod => new ModModel(mod)) - .OrderBy(p => Regex.Replace(p.Name.ToLower(), "[^a-z0-9]", "")) // ignore case, spaces, and special characters when sorting - ); - return this.View("Index", viewModel); + return this.View("Index", await this.FetchDataAsync()); + } + + + /********* + ** Private methods + *********/ + /// Asynchronously fetch mod metadata from the wiki. + public async Task FetchDataAsync() + { + return await this.Cache.GetOrCreateAsync($"{nameof(ModsController)}_mod_list", async entry => + { + WikiModEntry[] entries = await new ModToolkit().GetWikiCompatibilityListAsync(); + ModListModel model = new ModListModel( + stableVersion: "1.3.28", + betaVersion: "1.3.31-beta", + mods: entries + .Select(mod => new ModModel(mod)) + .OrderBy(p => Regex.Replace(p.Name.ToLower(), "[^a-z0-9]", "")) // ignore case, spaces, and special characters when sorting + ); + + entry.AbsoluteExpiration = DateTimeOffset.UtcNow.AddMinutes(this.SuccessCacheMinutes); + return model; + }); } } } -- cgit From 9af8cb86f1c2b37d6b5f95f1ab2acf6a7f757aa0 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 20 Oct 2018 15:14:26 -0400 Subject: correct instructions on log parser page --- src/SMAPI.Web/Views/LogParser/Index.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml index 1bd5558a..ce495477 100644 --- a/src/SMAPI.Web/Views/LogParser/Index.cshtml +++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml @@ -84,7 +84,7 @@ else if (Model.ParsedLog?.IsValid == true) On Mac:
  1. Open the Finder app.
  2. -
  3. Click Go at the top, then Enter Location.
  4. +
  5. Click Go at the top, then Go to Folder.
  6. Enter this exact text:
    ~/.config/StardewValley/ErrorLogs
  7. The log file is SMAPI-crash.txt if it exists, otherwise SMAPI-latest.txt.
-- cgit From 2b5db3ce7e37632422475239faa063c5bcc09064 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 20 Oct 2018 15:29:16 -0400 Subject: fix mod list routing (#597) --- src/SMAPI.Web/Startup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs index bf3ec9a1..82abf17d 100644 --- a/src/SMAPI.Web/Startup.cs +++ b/src/SMAPI.Web/Startup.cs @@ -147,7 +147,7 @@ namespace StardewModdingAPI.Web redirects.Add(new ConditionalRewriteSubdomainRule( shouldRewrite: req => req.Host.Host != "localhost" - && (req.Host.Host.StartsWith("api.") || req.Host.Host.StartsWith("log.")) + && (req.Host.Host.StartsWith("api.") || req.Host.Host.StartsWith("log.") || req.Host.Host.StartsWith("mods.")) && !req.Path.StartsWithSegments("/content") && !req.Path.StartsWithSegments("/favicon.ico") )); -- cgit From 39bacfa8688232e11850cdf2c0b0b4c953be1d76 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 20 Oct 2018 17:26:26 -0400 Subject: hide technical columns by default (#597) --- src/SMAPI.Web/Views/Mods/Index.cshtml | 18 ++++++++++++------ src/SMAPI.Web/wwwroot/Content/css/mods.css | 4 ++++ src/SMAPI.Web/wwwroot/Content/js/mods.js | 6 +++++- 3 files changed, 21 insertions(+), 7 deletions(-) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/Views/Mods/Index.cshtml b/src/SMAPI.Web/Views/Mods/Index.cshtml index 2b33fcaf..8d1b91ad 100644 --- a/src/SMAPI.Web/Views/Mods/Index.cshtml +++ b/src/SMAPI.Web/Views/Mods/Index.cshtml @@ -26,16 +26,22 @@ }
- - +
+ + +
+
+ + +
- - + + @@ -59,8 +65,8 @@ - - + diff --git a/src/SMAPI.Web/wwwroot/Content/css/mods.css b/src/SMAPI.Web/wwwroot/Content/css/mods.css index d250440f..fee01450 100644 --- a/src/SMAPI.Web/wwwroot/Content/css/mods.css +++ b/src/SMAPI.Web/wwwroot/Content/css/mods.css @@ -42,6 +42,10 @@ table.wikitable > caption { font-weight:bold } +#show-fields-option { + opacity: 0.7; +} + #mod-list .mod-page-links, #mod-list .mod-alt-authors, #mod-list .mod-alt-names, diff --git a/src/SMAPI.Web/wwwroot/Content/js/mods.js b/src/SMAPI.Web/wwwroot/Content/js/mods.js index 1b15b622..16c7cd5e 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/mods.js +++ b/src/SMAPI.Web/wwwroot/Content/js/mods.js @@ -4,7 +4,11 @@ var smapi = smapi || {}; var app; smapi.modList = function (mods) { // init data - var data = { mods: mods, search: "" }; + var data = { + mods: mods, + showAllFields: false, + search: "" + }; for (var i = 0; i < data.mods.length; i++) { var mod = mods[i]; -- cgit From b8c6747e891d789b1487013d7d26e19988a78597 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 20 Oct 2018 17:35:51 -0400 Subject: tone down background colors (#597) --- src/SMAPI.Web/wwwroot/Content/css/mods.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/wwwroot/Content/css/mods.css b/src/SMAPI.Web/wwwroot/Content/css/mods.css index fee01450..3b7a17ce 100644 --- a/src/SMAPI.Web/wwwroot/Content/css/mods.css +++ b/src/SMAPI.Web/wwwroot/Content/css/mods.css @@ -64,7 +64,7 @@ table.wikitable > caption { #mod-list tr[data-status="Ok"], #mod-list tr[data-status="Optional"] { - background: #9F9; + background: #BFB; } #mod-list tr[data-status="Workaround"], @@ -73,12 +73,12 @@ table.wikitable > caption { } #mod-list tr[data-status="Broken"] { - background: #F99; + background: #FBB; } #mod-list tr[data-status="Obsolete"], #mod-list tr[data-status="Abandoned"] { - background: #999; + background: #BBB; opacity: 0.7; } -- cgit From baaefc143aebf6b13ac91139ec8324c9867163e3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 20 Oct 2018 18:34:44 -0400 Subject: put focus in textbox for quick search (#597) --- src/SMAPI.Web/wwwroot/Content/js/mods.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/wwwroot/Content/js/mods.js b/src/SMAPI.Web/wwwroot/Content/js/mods.js index 16c7cd5e..488692e7 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/mods.js +++ b/src/SMAPI.Web/wwwroot/Content/js/mods.js @@ -57,4 +57,8 @@ smapi.modList = function (mods) { } } }); + + // put focus in textbox for quick search + if (!location.hash) + $("#search-box").focus(); }; -- cgit From b729ef012925ca00f2f9b4c6a2091d6cf78b239c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 20 Oct 2018 19:39:32 -0400 Subject: add table sorting (#597) --- src/SMAPI.Web/Views/Mods/Index.cshtml | 85 ++++++++++++---------- src/SMAPI.Web/wwwroot/Content/css/mods.css | 23 +++++- .../Content/js/external/jquery-tablesorter.js | 5 ++ src/SMAPI.Web/wwwroot/Content/js/mods.js | 7 ++ 4 files changed, 76 insertions(+), 44 deletions(-) create mode 100644 src/SMAPI.Web/wwwroot/Content/js/external/jquery-tablesorter.js (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/Views/Mods/Index.cshtml b/src/SMAPI.Web/Views/Mods/Index.cshtml index 8d1b91ad..3626c4d8 100644 --- a/src/SMAPI.Web/Views/Mods/Index.cshtml +++ b/src/SMAPI.Web/Views/Mods/Index.cshtml @@ -7,6 +7,7 @@ + - + } -

This page lists all known SMAPI mods, whether they're compatible with the latest versions of Stardew Valley and SMAPI, and how to fix broken mods if possible. The list is updated every few days. (You can help edit this list!)

+
+

This page lists all known SMAPI mods, whether they're compatible with the latest versions of Stardew Valley and SMAPI, and how to fix broken mods if possible. The list is updated every few days. (You can help edit this list!)

-@if (Model.BetaVersion != null) -{ -
-

Note: "SDV beta only" means Stardew Valley @Model.BetaVersion-beta; if you didn't opt in to the beta, you have the stable version and can ignore that line. If a mod doesn't have a "SDV beta only" line, the compatibility applies to both versions of the game.

-
-} +

If a mod doesn't work after following the instructions below, check the troubleshooting guide or ask for help.

+ + @if (Model.BetaVersion != null) + { +

Note: "SDV beta only" means Stardew Valley @Model.BetaVersion-beta; if you didn't opt in to the beta, you have the stable version and can ignore that line. If a mod doesn't have a "SDV beta only" line, the compatibility applies to both versions of the game.

+ } +
diff --git a/src/SMAPI.Web/wwwroot/Content/css/mods.css b/src/SMAPI.Web/wwwroot/Content/css/mods.css index b11c48d1..9f82e3e6 100644 --- a/src/SMAPI.Web/wwwroot/Content/css/mods.css +++ b/src/SMAPI.Web/wwwroot/Content/css/mods.css @@ -5,13 +5,11 @@ max-width: calc(100% - 2em); /* allow for wider table if room available */ } -#blurb { - margin-top: 0; +#intro { width: 50em; } #beta-blurb { - width: 50em; margin-bottom: 2em; padding: 1em; border: 3px solid darkgreen; -- cgit From 12c06afe144b06d26d69b10c3527ec1d2c90bdca Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 21 Oct 2018 12:32:45 -0400 Subject: update & standardise CDN script references --- src/SMAPI.Web/Views/Index/Index.cshtml | 2 +- src/SMAPI.Web/Views/LogParser/Index.cshtml | 4 ++-- src/SMAPI.Web/Views/Mods/Index.cshtml | 6 +++--- src/SMAPI.Web/wwwroot/Content/js/external/jquery-tablesorter.js | 5 ----- 4 files changed, 6 insertions(+), 11 deletions(-) delete mode 100644 src/SMAPI.Web/wwwroot/Content/js/external/jquery-tablesorter.js (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/Views/Index/Index.cshtml b/src/SMAPI.Web/Views/Index/Index.cshtml index 6eb82e64..a5a82121 100644 --- a/src/SMAPI.Web/Views/Index/Index.cshtml +++ b/src/SMAPI.Web/Views/Index/Index.cshtml @@ -4,7 +4,7 @@ @model StardewModdingAPI.Web.ViewModels.IndexModel @section Head { - + } diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml index ce495477..36eb9bb5 100644 --- a/src/SMAPI.Web/Views/LogParser/Index.cshtml +++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml @@ -18,8 +18,8 @@ } - - + + - - + + + @@ -16,7 +19,7 @@
- Download SMAPI @Model.StableVersion.Version
+ Download SMAPI @Model.StableVersion.Version

} - Player guide
+ +

Get help

@@ -55,7 +61,7 @@
@Html.Raw(Markdig.Markdown.ToHtml(Model.StableVersion.Description))
-

See the release notes and mod compatibility list for more info.

+

See the release notes and mod compatibility list for more info.

} else { @@ -64,13 +70,13 @@ else
@Html.Raw(Markdig.Markdown.ToHtml(Model.StableVersion.Description))
-

See the release notes and mod compatibility list for more info.

+

See the release notes and mod compatibility list for more info.

SMAPI @Model.BetaVersion.Version?

@Html.Raw(Markdig.Markdown.ToHtml(Model.BetaVersion.Description))
-

See the release notes and mod compatibility list for more info.

+

See the release notes and mod compatibility list for more info.

} diff --git a/src/SMAPI.Web/Views/Index/Privacy.cshtml b/src/SMAPI.Web/Views/Index/Privacy.cshtml new file mode 100644 index 00000000..ca99eef6 --- /dev/null +++ b/src/SMAPI.Web/Views/Index/Privacy.cshtml @@ -0,0 +1,43 @@ +@using Microsoft.Extensions.Options +@using StardewModdingAPI.Web.Framework.ConfigModels +@inject IOptions SiteConfig +@{ + ViewData["Title"] = "SMAPI privacy notes"; +} +@section Head { + +} + +← back to SMAPI page + +

SMAPI is an open-source and non-profit project. Your privacy is important, so this page explains what information SMAPI uses and transmits. This page is informational only, it's not a legal document.

+ +

Principles

+
    +
  1. SMAPI collects the minimum information needed to enable its features (see below).
  2. +
  3. SMAPI does not collect telemetry, analytics, etc.
  4. +
  5. SMAPI will never sell your information.
  6. +
+ +

Data collected and transmitted

+

Web logging

+

This website and SMAPI's web API are hosted by Amazon Web Services. Their servers may automatically collect diagnostics like your IP address, but this information is not visible to SMAPI's web application or developers. For more information, see the Amazon Privacy Notice.

+ +

Update checks

+

SMAPI notifies you when there's a new version of SMAPI or your mods available. To do so, it sends your SMAPI and mod versions to its web API. No personal information is stored by the web application, but see web logging.

+ +

You can disable update checks, and no information will be transmitted to the web API. To do so:

+
    +
  1. find your game folder;
  2. +
  3. open the smapi-internal/StardewModdingAPI.config.json file in a text editor;
  4. +
  5. change "CheckForUpdates": true to "CheckForUpdates": false.
  6. +
+ +

Log parser

+

The log parser page lets you store a log file for analysis and sharing. The log data is stored indefinitely in an obfuscated form as unlisted pastes in Pastebin. No personal information is stored by the log parser beyond what you choose to upload, but see web logging and the Pastebin Privacy Statement.

+ +

Multiplayer sync

+

As part of its multiplayer API, SMAPI transmits basic context to players you connect to (mainly your OS, SMAPI version, game version, and installed mods). This is used to enable multiplayer features like inter-mod messages, compatibility checks, etc. Although this information is normally hidden from players, it may be visible due to mods or configuration changes.

+ +

Custom mods

+

Mods may collect and transmit any information. Mods (except those provided as part of the SMAPI download) are not covered by this page. Install third-party mods at your own risk.

diff --git a/src/SMAPI.Web/wwwroot/Content/css/index.css b/src/SMAPI.Web/wwwroot/Content/css/index.css index 514e1a5c..979af4af 100644 --- a/src/SMAPI.Web/wwwroot/Content/css/index.css +++ b/src/SMAPI.Web/wwwroot/Content/css/index.css @@ -93,6 +93,11 @@ h1 { display: block; } +.sublinks { + font-size: 0.9em; + margin-bottom: 1em; +} + /********* ** Subsections *********/ diff --git a/src/SMAPI.Web/wwwroot/Content/css/privacy.css b/src/SMAPI.Web/wwwroot/Content/css/privacy.css new file mode 100644 index 00000000..94bc68a9 --- /dev/null +++ b/src/SMAPI.Web/wwwroot/Content/css/privacy.css @@ -0,0 +1,3 @@ +h3 { + border: 0; +} -- cgit From 0f231064d54316853912294fed603444f9faf293 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 5 Nov 2018 16:25:17 -0500 Subject: disable three mods broken by Harmony update --- src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'src/SMAPI.Web') diff --git a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json b/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json index 6f8d9c40..b16cb99f 100644 --- a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json +++ b/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json @@ -115,6 +115,11 @@ "MapRemoteVersions": { "1.3.1": "1.3" } // manifest not updated }, + "BJS Night Sounds": { + "ID": "BunnyJumps.BJSNightSounds", + "~1.0.0 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+ + }, + "Casks Anywhere": { "ID": "CasksAnywhere", "MapLocalVersions": { "1.1-alpha": "1.1" } @@ -194,7 +199,12 @@ "Fishing Adjust": { "ID": "shuaiz.FishingAdjustMod", - "~2.0.1 | Status": "AssumeBroken" // Method not found: 'Void Harmony.HarmonyInstance.Patch(System.Reflection.MethodBase, Harmony.HarmonyMethod, Harmony.HarmonyMethod, Harmony.HarmonyMethod)' + "~2.0.1 | Status": "AssumeBroken" // Method not found: 'Void Harmony.HarmonyInstance.Patch(System.Reflection.MethodBase, Harmony.HarmonyMethod, Harmony.HarmonyMethod, Harmony.HarmonyMethod)' + }, + + "Fishing Automaton": { + "ID": "Drynwynn.FishingAutomaton", + "~1.1 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+ }, "Fix Scythe Exp": { @@ -263,6 +273,11 @@ "MapLocalVersions": { "2.1": "1.3" } // 1.3 had wrong version in manifest }, + "No Added Flying Mine Monsters": { + "ID": "Drynwynn.NoAddedFlyingMineMonsters", + "~1.1 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+ + }, + "No Debug Mode": { "ID": "NoDebugMode", "~ | Status": "Obsolete", -- cgit From 9560baeb71ca17c8b86b3674daddd13765ba0f24 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 9 Nov 2018 17:35:56 -0500 Subject: add filters to mod compatibility list (#597) --- docs/release-notes.md | 4 +- src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs | 2 + src/SMAPI.Web/ViewModels/ModModel.cs | 3 + src/SMAPI.Web/Views/Mods/Index.cshtml | 34 +++-- src/SMAPI.Web/wwwroot/Content/css/mods.css | 47 +++++-- src/SMAPI.Web/wwwroot/Content/js/mods.js | 144 ++++++++++++++++++++-- 6 files changed, 201 insertions(+), 33 deletions(-) (limited to 'src/SMAPI.Web') diff --git a/docs/release-notes.md b/docs/release-notes.md index b9a73f99..9d587ab7 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -10,7 +10,7 @@ * You can now mark a mod folder ignored by starting the name with a dot (like `.disabled mods`). * Improved various error messages to be more clear and intuitive. * SMAPI now prevents a crash caused by mods adding dialogue the game can't parse. - * When you have an older game version, SMAPI now recommends a compatible SMAPI version in its error. + * SMAPI now recommends a compatible SMAPI version if you have an older game version. * Fixed transparency issues on Linux/Mac for some mod images. * Fixed error when a mod manifest is corrupted. * Fixed error when a mod adds an unnamed location. @@ -50,7 +50,7 @@ * Suppressed the game's 'added crickets' debug output. * Updated dependencies (Harmony 1.0.9.1 → 1.2.0.1, Mono.Cecil 0.10 → 0.10.1). * **Deprecations:** - * Non-string manifest versions are now deprecated and will no longer work in SMAPI 3.0. Affected mods should be updated to use a string version, like `"Version": "1.0.0"`. + * Non-string manifest versions are now deprecated and will stop working in SMAPI 3.0. Affected mods should use a string version, like `"Version": "1.0.0"`. * `ISemanticVersion.Build` is now deprecated and will be removed in SMAPI 3.0. Affected mods should use `ISemanticVersion.PrereleaseTag` instead. * **Breaking changes:** * `helper.ModRegistry` now returns `IModInfo` instead of `IManifest` directly. This lets SMAPI return more metadata about mods. diff --git a/src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs b/src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs index 61756176..85bf1e46 100644 --- a/src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs +++ b/src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs @@ -29,6 +29,8 @@ namespace StardewModdingAPI.Web.ViewModels public ModCompatibilityModel(WikiCompatibilityInfo info) { this.Status = info.Status.ToString(); + this.Status = this.Status.Substring(0, 1).ToLower() + this.Status.Substring(1); + this.Summary = info.Summary; this.BrokeIn = info.BrokeIn; if (info.UnofficialVersion != null) diff --git a/src/SMAPI.Web/ViewModels/ModModel.cs b/src/SMAPI.Web/ViewModels/ModModel.cs index 309ed828..0e7d2076 100644 --- a/src/SMAPI.Web/ViewModels/ModModel.cs +++ b/src/SMAPI.Web/ViewModels/ModModel.cs @@ -40,6 +40,9 @@ namespace StardewModdingAPI.Web.ViewModels /// A unique identifier for the mod that can be used in an anchor URL. public string Slug { get; set; } + /// The sites where the mod can be downloaded. + public string[] ModPageSites => this.ModPages.Select(p => p.Text).ToArray(); + /********* ** Public methods diff --git a/src/SMAPI.Web/Views/Mods/Index.cshtml b/src/SMAPI.Web/Views/Mods/Index.cshtml index b326fd36..372d6706 100644 --- a/src/SMAPI.Web/Views/Mods/Index.cshtml +++ b/src/SMAPI.Web/Views/Mods/Index.cshtml @@ -4,11 +4,11 @@ ViewData["Title"] = "SMAPI mod compatibility"; } @section Head { - + - +
mod name links author compatibilitybroke incodebroke incode  
+ source no source