Exemplo n.º 1
0
        /// <summary>Construct an instance.</summary>
        /// <param name="wiki">The mod metadata from the wiki (if available).</param>
        /// <param name="db">The mod metadata from SMAPI's internal DB (if available).</param>
        public ModExtendedMetadataModel(WikiModEntry wiki, ModDataRecord db)
        {
            // wiki data
            if (wiki != null)
            {
                this.ID              = wiki.ID;
                this.Name            = wiki.Name.FirstOrDefault();
                this.NexusID         = wiki.NexusID;
                this.ChucklefishID   = wiki.ChucklefishID;
                this.ModDropID       = wiki.ModDropID;
                this.GitHubRepo      = wiki.GitHubRepo;
                this.CustomSourceUrl = wiki.CustomSourceUrl;
                this.CustomUrl       = wiki.CustomUrl;

                this.Smapi3Status = wiki.Smapi3Status;
                this.Smapi3Url    = wiki.Smapi3Url;

                this.CompatibilityStatus  = wiki.Compatibility.Status;
                this.CompatibilitySummary = wiki.Compatibility.Summary;

                this.BetaCompatibilityStatus  = wiki.BetaCompatibility?.Status;
                this.BetaCompatibilitySummary = wiki.BetaCompatibility?.Summary;
            }

            // internal DB data
            if (db != null)
            {
                this.ID   = this.ID.Union(db.FormerIDs).ToArray();
                this.Name = this.Name ?? db.DisplayName;
            }
        }
Exemplo n.º 2
0
        /// <summary>Get the web URLs for the mod pages, if any.</summary>
        /// <param name="entry">The mod metadata.</param>
        private IEnumerable <ModLinkModel> 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"));
            }
            if (entry.ModDropID.HasValue)
            {
                anyFound = true;
                yield return(new ModLinkModel($"https://www.moddrop.com/sdv/mod/{entry.ModDropID}", "ModDrop"));
            }

            // 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"));
            }
        }
Exemplo n.º 3
0
        /// <summary>Construct an instance.</summary>
        /// <param name="mod">The mod data.</param>
        public CachedWikiMod(WikiModEntry mod)
        {
            // tracking
            this.LastUpdated = DateTimeOffset.UtcNow;

            // mod info
            this.ID              = mod.ID;
            this.Name            = mod.Name;
            this.Author          = mod.Author;
            this.NexusID         = mod.NexusID;
            this.ChucklefishID   = mod.ChucklefishID;
            this.ModDropID       = mod.ModDropID;
            this.GitHubRepo      = mod.GitHubRepo;
            this.CustomSourceUrl = mod.CustomSourceUrl;
            this.CustomUrl       = mod.CustomUrl;
            this.ContentPackFor  = mod.ContentPackFor;
            this.MetadataLinks   = mod.MetadataLinks;
            this.Warnings        = mod.Warnings;
            this.DevNote         = mod.DevNote;
            this.Anchor          = mod.Anchor;

            // stable compatibility
            this.MainStatus            = mod.Compatibility.Status;
            this.MainSummary           = mod.Compatibility.Summary;
            this.MainBrokeIn           = mod.Compatibility.BrokeIn;
            this.MainUnofficialVersion = mod.Compatibility.UnofficialVersion?.ToString();
            this.MainUnofficialUrl     = mod.Compatibility.UnofficialUrl;

            // beta compatibility
            this.BetaStatus            = mod.BetaCompatibility?.Status;
            this.BetaSummary           = mod.BetaCompatibility?.Summary;
            this.BetaBrokeIn           = mod.BetaCompatibility?.BrokeIn;
            this.BetaUnofficialVersion = mod.BetaCompatibility?.UnofficialVersion?.ToString();
            this.BetaUnofficialUrl     = mod.BetaCompatibility?.UnofficialUrl;
        }
Exemplo n.º 4
0
 /*********
 ** Private methods
 *********/
 /// <summary>Get the web URL for the mod's source code repository, if any.</summary>
 /// <param name="entry">The mod metadata.</param>
 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);
 }
Exemplo n.º 5
0
        /// <summary>Reconstruct the original model.</summary>
        public WikiModEntry GetModel()
        {
            var mod = new WikiModEntry
            {
                ID              = this.ID,
                Name            = this.Name,
                Author          = this.Author,
                NexusID         = this.NexusID,
                ChucklefishID   = this.ChucklefishID,
                CurseForgeID    = this.CurseForgeID,
                CurseForgeKey   = this.CurseForgeKey,
                ModDropID       = this.ModDropID,
                GitHubRepo      = this.GitHubRepo,
                CustomSourceUrl = this.CustomSourceUrl,
                CustomUrl       = this.CustomUrl,
                ContentPackFor  = this.ContentPackFor,
                Warnings        = this.Warnings,
                MetadataLinks   = this.MetadataLinks,
                DevNote         = this.DevNote,
                Anchor          = this.Anchor,

                // stable compatibility
                Compatibility = new WikiCompatibilityInfo
                {
                    Status            = this.MainStatus,
                    Summary           = this.MainSummary,
                    BrokeIn           = this.MainBrokeIn,
                    UnofficialVersion = this.MainUnofficialVersion != null ? new SemanticVersion(this.MainUnofficialVersion) : null,
                    UnofficialUrl     = this.MainUnofficialUrl
                },

                // version maps
                MapLocalVersions  = this.MapLocalVersions,
                MapRemoteVersions = this.MapRemoteVersions
            };

            // beta compatibility
            if (this.BetaStatus != null)
            {
                mod.BetaCompatibility = new WikiCompatibilityInfo
                {
                    Status            = this.BetaStatus.Value,
                    Summary           = this.BetaSummary,
                    BrokeIn           = this.BetaBrokeIn,
                    UnofficialVersion = this.BetaUnofficialVersion != null ? new SemanticVersion(this.BetaUnofficialVersion) : null,
                    UnofficialUrl     = this.BetaUnofficialUrl
                };
            }

            return(mod);
        }
Exemplo n.º 6
0
 /*********
 ** Public methods
 *********/
 /// <summary>Construct an instance.</summary>
 /// <param name="entry">The mod metadata.</param>
 public ModModel(WikiModEntry entry)
 {
     // basic info
     this.Name              = entry.Name.FirstOrDefault();
     this.AlternateNames    = string.Join(", ", entry.Name.Skip(1).ToArray());
     this.Author            = entry.Author.FirstOrDefault();
     this.AlternateAuthors  = string.Join(", ", entry.Author.Skip(1).ToArray());
     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.Warnings          = entry.Warnings;
     this.Slug              = entry.Anchor;
 }
Exemplo n.º 7
0
        /// <summary>Construct an instance.</summary>
        /// <param name="wiki">The mod metadata from the wiki (if available).</param>
        /// <param name="db">The mod metadata from SMAPI's internal DB (if available).</param>
        /// <param name="main">The main version.</param>
        /// <param name="optional">The latest optional version, if newer than <paramref name="main"/>.</param>
        /// <param name="unofficial">The latest unofficial version, if newer than <paramref name="main"/> and <paramref name="optional"/>.</param>
        /// <param name="unofficialForBeta">The latest unofficial version for the current Stardew Valley or SMAPI beta, if any.</param>
        public ModExtendedMetadataModel(WikiModEntry wiki, ModDataRecord db, ModEntryVersionModel main, ModEntryVersionModel optional, ModEntryVersionModel unofficial, ModEntryVersionModel unofficialForBeta)
        {
            // versions
            this.Main              = main;
            this.Optional          = optional;
            this.Unofficial        = unofficial;
            this.UnofficialForBeta = unofficialForBeta;

            // wiki data
            if (wiki != null)
            {
                this.ID              = wiki.ID;
                this.Name            = wiki.Name.FirstOrDefault();
                this.NexusID         = wiki.NexusID;
                this.ChucklefishID   = wiki.ChucklefishID;
                this.CurseForgeID    = wiki.CurseForgeID;
                this.CurseForgeKey   = wiki.CurseForgeKey;
                this.ModDropID       = wiki.ModDropID;
                this.GitHubRepo      = wiki.GitHubRepo;
                this.CustomSourceUrl = wiki.CustomSourceUrl;
                this.CustomUrl       = wiki.CustomUrl;

                this.CompatibilityStatus  = wiki.Compatibility.Status;
                this.CompatibilitySummary = wiki.Compatibility.Summary;
                this.BrokeIn = wiki.Compatibility.BrokeIn;

                this.BetaCompatibilityStatus  = wiki.BetaCompatibility?.Status;
                this.BetaCompatibilitySummary = wiki.BetaCompatibility?.Summary;
                this.BetaBrokeIn = wiki.BetaCompatibility?.BrokeIn;

                this.ChangeLocalVersions  = wiki.Overrides?.ChangeLocalVersions?.ToString();
                this.ChangeRemoteVersions = wiki.Overrides?.ChangeRemoteVersions?.ToString();
                this.ChangeUpdateKeys     = wiki.Overrides?.ChangeUpdateKeys?.ToString();
            }

            // internal DB data
            if (db != null)
            {
                this.ID = this.ID.Union(db.FormerIDs).ToArray();
                this.Name ??= db.DisplayName;
            }
        }
Exemplo n.º 8
0
        /// <summary>Get every available update key based on the available mod metadata, including duplicates and keys which should be filtered.</summary>
        /// <param name="specifiedKeys">The specified update keys.</param>
        /// <param name="record">The mod's entry in SMAPI's internal database.</param>
        /// <param name="entry">The mod's entry in the wiki list.</param>
        private IEnumerable <string> GetUnfilteredUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry)
        {
            // specified update keys
            foreach (string key in specifiedKeys ?? Array.Empty <string>())
            {
                if (!string.IsNullOrWhiteSpace(key))
                {
                    yield return(key.Trim());
                }
            }

            // default update key
            {
                string defaultKey = record?.GetDefaultUpdateKey();
                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()));
                }
                if (entry.ModDropID.HasValue)
                {
                    yield return(UpdateKey.GetString(ModSiteKey.ModDrop, entry.ModDropID.ToString()));
                }
                if (entry.CurseForgeID.HasValue)
                {
                    yield return(UpdateKey.GetString(ModSiteKey.CurseForge, entry.CurseForgeID.ToString()));
                }
                if (entry.ChucklefishID.HasValue)
                {
                    yield return(UpdateKey.GetString(ModSiteKey.Chucklefish, entry.ChucklefishID.ToString()));
                }
            }

            // overrides from wiki
            foreach (string key in entry?.ChangeUpdateKeys ?? Array.Empty <string>())
            {
                if (key.StartsWith('+'))
                {
                    yield return(key.Substring(1));
                }
                else if (!key.StartsWith("-"))
                {
                    yield return(key);
                }
            }
        }
Exemplo n.º 9
0
        /// <summary>Get update keys based on the available mod metadata, while maintaining the precedence order.</summary>
        /// <param name="specifiedKeys">The specified update keys.</param>
        /// <param name="record">The mod's entry in SMAPI's internal database.</param>
        /// <param name="entry">The mod's entry in the wiki list.</param>
        private IEnumerable <UpdateKey> GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry)
        {
            // get unique update keys
            List <UpdateKey> updateKeys = this.GetUnfilteredUpdateKeys(specifiedKeys, record, entry)
                                          .Select(UpdateKey.Parse)
                                          .Distinct()
                                          .ToList();

            // apply remove overrides from wiki
            {
                var removeKeys = new HashSet <UpdateKey>(
                    from key in entry?.ChangeUpdateKeys ?? new string[0]
                    where key.StartsWith('-')
                    select UpdateKey.Parse(key.Substring(1))
                    );
                if (removeKeys.Any())
                {
                    updateKeys.RemoveAll(removeKeys.Contains);
                }
            }

            // 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
            {
                var removeKeys = new HashSet <UpdateKey>();
                foreach (var key in updateKeys)
                {
                    if (key.Subkey != null)
                    {
                        removeKeys.Add(new UpdateKey(key.Site, key.ID, null));
                    }
                }
                if (removeKeys.Any())
                {
                    updateKeys.RemoveAll(removeKeys.Contains);
                }
            }

            return(updateKeys);
        }
Exemplo n.º 10
0
        /*********
        ** Private methods
        *********/
        /// <summary>Get the metadata for a mod.</summary>
        /// <param name="search">The mod data to match.</param>
        /// <param name="wikiData">The wiki data.</param>
        /// <param name="includeExtendedMetadata">Whether to include extended metadata for each mod.</param>
        /// <param name="apiVersion">The SMAPI version installed by the player.</param>
        /// <returns>Returns the mod data if found, else <c>null</c>.</returns>
        private async Task <ModEntryModel> GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata, ISemanticVersion apiVersion)
        {
            // cross-reference data
            ModDataRecord record    = this.ModDatabase.Get(search.ID);
            WikiModEntry  wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.OrdinalIgnoreCase));

            UpdateKey[]       updateKeys  = this.GetUpdateKeys(search.UpdateKeys, record, wikiEntry).ToArray();
            ModOverrideConfig overrides   = this.Config.Value.ModOverrides.FirstOrDefault(p => p.ID.Equals(search.ID?.Trim(), StringComparison.OrdinalIgnoreCase));
            bool allowNonStandardVersions = overrides?.AllowNonStandardVersions ?? false;

            // get latest versions
            ModEntryModel result = new ModEntryModel {
                ID = search.ID
            };
            IList <string>       errors            = new List <string>();
            ModEntryVersionModel main              = null;
            ModEntryVersionModel optional          = null;
            ModEntryVersionModel unofficial        = null;
            ModEntryVersionModel unofficialForBeta = null;

            foreach (UpdateKey updateKey in updateKeys)
            {
                // 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', with an optional subkey like 'Nexus:541@subkey'.");
                    continue;
                }

                // fetch data
                ModInfoModel data = await this.GetInfoForUpdateKeyAsync(updateKey, allowNonStandardVersions, wikiEntry?.MapRemoteVersions);

                if (data.Status != RemoteModStatus.Ok)
                {
                    errors.Add(data.Error ?? data.Status.ToString());
                    continue;
                }

                // handle versions
                if (this.IsNewer(data.Version, main?.Version))
                {
                    main = new ModEntryVersionModel(data.Version, data.Url);
                }
                if (this.IsNewer(data.PreviewVersion, optional?.Version))
                {
                    optional = new ModEntryVersionModel(data.PreviewVersion, data.Url);
                }
            }

            // get unofficial version
            if (wikiEntry?.Compatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, main?.Version) && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, optional?.Version))
            {
                unofficial = new ModEntryVersionModel(wikiEntry.Compatibility.UnofficialVersion, $"{this.Url.PlainAction("Index", "Mods", absoluteUrl: true)}#{wikiEntry.Anchor}");
            }

            // get unofficial version for beta
            if (wikiEntry?.HasBetaInfo == true)
            {
                if (wikiEntry.BetaCompatibility.Status == WikiCompatibilityStatus.Unofficial)
                {
                    if (wikiEntry.BetaCompatibility.UnofficialVersion != null)
                    {
                        unofficialForBeta = (wikiEntry.BetaCompatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, main?.Version) && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, optional?.Version))
                            ? new ModEntryVersionModel(wikiEntry.BetaCompatibility.UnofficialVersion, $"{this.Url.PlainAction("Index", "Mods", absoluteUrl: true)}#{wikiEntry.Anchor}")
                            : null;
                    }
                    else
                    {
                        unofficialForBeta = unofficial;
                    }
                }
            }

            // fallback to preview if latest is invalid
            if (main == null && optional != null)
            {
                main     = optional;
                optional = null;
            }

            // special cases
            if (overrides?.SetUrl != null)
            {
                if (main != null)
                {
                    main.Url = overrides.SetUrl;
                }
                if (optional != null)
                {
                    optional.Url = overrides.SetUrl;
                }
            }

            // get recommended update (if any)
            ISemanticVersion installedVersion = this.ModSites.GetMappedVersion(search.InstalledVersion?.ToString(), wikiEntry?.MapLocalVersions, allowNonStandard: allowNonStandardVersions);

            if (apiVersion != null && installedVersion != null)
            {
                // get newer versions
                List <ModEntryVersionModel> updates = new List <ModEntryVersionModel>();
                if (this.IsRecommendedUpdate(installedVersion, main?.Version, useBetaChannel: true))
                {
                    updates.Add(main);
                }
                if (this.IsRecommendedUpdate(installedVersion, optional?.Version, useBetaChannel: installedVersion.IsPrerelease() || search.IsBroken))
                {
                    updates.Add(optional);
                }
                if (this.IsRecommendedUpdate(installedVersion, unofficial?.Version, useBetaChannel: true))
                {
                    updates.Add(unofficial);
                }
                if (this.IsRecommendedUpdate(installedVersion, unofficialForBeta?.Version, useBetaChannel: apiVersion.IsPrerelease()))
                {
                    updates.Add(unofficialForBeta);
                }

                // get newest version
                ModEntryVersionModel newest = null;
                foreach (ModEntryVersionModel update in updates)
                {
                    if (newest == null || update.Version.IsNewerThan(newest.Version))
                    {
                        newest = update;
                    }
                }

                // set field
                result.SuggestedUpdate = newest != null
                    ? new ModEntryVersionModel(newest.Version, newest.Url)
                    : null;
            }

            // add extended metadata
            if (includeExtendedMetadata)
            {
                result.Metadata = new ModExtendedMetadataModel(wikiEntry, record, main: main, optional: optional, unofficial: unofficial, unofficialForBeta: unofficialForBeta);
            }

            // add result
            result.Errors = errors.ToArray();
            return(result);
        }
Exemplo n.º 11
0
        /// <summary>Get update keys based on the available mod metadata, while maintaining the precedence order.</summary>
        /// <param name="specifiedKeys">The specified update keys.</param>
        /// <param name="record">The mod's entry in SMAPI's internal database.</param>
        /// <param name="entry">The mod's entry in the wiki list.</param>
        public IEnumerable <UpdateKey> GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry)
        {
            IEnumerable <string> 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}");
                    }
                    if (entry.ModDropID.HasValue)
                    {
                        yield return($"ModDrop:{entry.ModDropID}");
                    }
                }
            }

            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);
                }
            }
        }
Exemplo n.º 12
0
        /*********
        ** Private methods
        *********/
        /// <summary>Get the metadata for a mod.</summary>
        /// <param name="search">The mod data to match.</param>
        /// <param name="wikiData">The wiki data.</param>
        /// <param name="includeExtendedMetadata">Whether to include extended metadata for each mod.</param>
        /// <returns>Returns the mod data if found, else <c>null</c>.</returns>
        private async Task <ModEntryModel> GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata)
        {
            // cross-reference data
            ModDataRecord record    = this.ModDatabase.Get(search.ID);
            WikiModEntry  wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.InvariantCultureIgnoreCase));

            UpdateKey[] updateKeys = this.GetUpdateKeys(search.UpdateKeys, record, wikiEntry).ToArray();

            // get latest versions
            ModEntryModel result = new ModEntryModel {
                ID = search.ID
            };
            IList <string> errors = new List <string>();

            foreach (UpdateKey updateKey in updateKeys)
            {
                // 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'.");
                    continue;
                }

                // fetch data
                ModInfoModel data = await this.GetInfoForUpdateKeyAsync(updateKey);

                if (data.Error != null)
                {
                    errors.Add(data.Error);
                    continue;
                }

                // handle main version
                if (data.Version != null)
                {
                    if (!SemanticVersion.TryParse(data.Version, out ISemanticVersion version))
                    {
                        errors.Add($"The update key '{updateKey}' matches a mod with invalid semantic version '{data.Version}'.");
                        continue;
                    }

                    if (this.IsNewer(version, result.Main?.Version))
                    {
                        result.Main = new ModEntryVersionModel(version, data.Url);
                    }
                }

                // handle optional version
                if (data.PreviewVersion != null)
                {
                    if (!SemanticVersion.TryParse(data.PreviewVersion, out ISemanticVersion version))
                    {
                        errors.Add($"The update key '{updateKey}' matches a mod with invalid optional semantic version '{data.PreviewVersion}'.");
                        continue;
                    }

                    if (this.IsNewer(version, result.Optional?.Version))
                    {
                        result.Optional = new ModEntryVersionModel(version, data.Url);
                    }
                }
            }

            // get unofficial version
            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.CompatibilityPageUrl}/#{wikiEntry.Anchor}");
            }

            // get unofficial version for beta
            if (wikiEntry?.HasBetaInfo == true)
            {
                result.HasBetaInfo = true;
                if (wikiEntry.BetaCompatibility.Status == WikiCompatibilityStatus.Unofficial)
                {
                    if (wikiEntry.BetaCompatibility.UnofficialVersion != null)
                    {
                        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.CompatibilityPageUrl}/#{wikiEntry.Anchor}")
                            : null;
                    }
                    else
                    {
                        result.UnofficialForBeta = result.Unofficial;
                    }
                }
            }

            // fallback to preview if latest is invalid
            if (result.Main == null && result.Optional != null)
            {
                result.Main     = result.Optional;
                result.Optional = null;
            }

            // special cases
            if (result.ID == "Pathoschild.SMAPI")
            {
                if (result.Main != null)
                {
                    result.Main.Url = "https://smapi.io/";
                }
                if (result.Optional != null)
                {
                    result.Optional.Url = "https://smapi.io/";
                }
            }

            // add extended metadata
            if (includeExtendedMetadata && (wikiEntry != null || record != null))
            {
                result.Metadata = new ModExtendedMetadataModel(wikiEntry, record);
            }

            // add result
            result.Errors = errors.ToArray();
            return(result);
        }
Exemplo n.º 13
0
        /// <summary>Get update keys based on the available mod metadata, while maintaining the precedence order.</summary>
        /// <param name="specifiedKeys">The specified update keys.</param>
        /// <param name="record">The mod's entry in SMAPI's internal database.</param>
        /// <param name="entry">The mod's entry in the wiki list.</param>
        public IEnumerable <string> GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry)
        {
            IEnumerable <string> 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 <string> seen = new HashSet <string>(StringComparer.InvariantCulture);

            foreach (string key in GetRaw())
            {
                if (!string.IsNullOrWhiteSpace(key) && seen.Add(key))
                {
                    yield return(key);
                }
            }
        }
Exemplo n.º 14
0
        /// <summary>Get update keys based on the available mod metadata, while maintaining the precedence order.</summary>
        /// <param name="specifiedKeys">The specified update keys.</param>
        /// <param name="record">The mod's entry in SMAPI's internal database.</param>
        /// <param name="entry">The mod's entry in the wiki list.</param>
        private IEnumerable <UpdateKey> GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry)
        {
            // get unique update keys
            List <UpdateKey> updateKeys = this.GetUnfilteredUpdateKeys(specifiedKeys, record, entry)
                                          .Select(UpdateKey.Parse)
                                          .Distinct()
                                          .ToList();

            // apply overrides from wiki
            if (entry?.Overrides?.ChangeUpdateKeys?.HasChanges == true)
            {
                List <string> newKeys = updateKeys.Select(p => p.ToString()).ToList();
                entry.Overrides.ChangeUpdateKeys.Apply(newKeys);
                updateKeys = newKeys.Select(UpdateKey.Parse).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
            {
                var removeKeys = new HashSet <UpdateKey>();
                foreach (var key in updateKeys)
                {
                    if (key.Subkey != null)
                    {
                        removeKeys.Add(new UpdateKey(key.Site, key.ID, null));
                    }
                }
                if (removeKeys.Any())
                {
                    updateKeys.RemoveAll(removeKeys.Contains);
                }
            }

            return(updateKeys);
        }