diff --git a/MinecraftLaunch.Base/Enums/AdditionalFileType.cs b/MinecraftLaunch.Base/Enums/AdditionalFileType.cs new file mode 100644 index 0000000..e9065ba --- /dev/null +++ b/MinecraftLaunch.Base/Enums/AdditionalFileType.cs @@ -0,0 +1,8 @@ + +namespace MinecraftLaunch.Base.Enums; + +public enum AdditionalFileType +{ + RequiredResourcePack, + OptionalResourcePack +} diff --git a/MinecraftLaunch.Base/Enums/CurseForgeFileStatus.cs b/MinecraftLaunch.Base/Enums/CurseForgeFileStatus.cs new file mode 100644 index 0000000..bd39e00 --- /dev/null +++ b/MinecraftLaunch.Base/Enums/CurseForgeFileStatus.cs @@ -0,0 +1,29 @@ + +namespace MinecraftLaunch.Base.Enums; + +public enum CurseForgeFileStatus +{ + Processing = 1, + ChangesRequired, + UnderReview, + Approved, + Rejected, + MalwareDetected, + Deleted, + Archived, + Testing, + Released, + ReadyForReview, + Deprecated, + Baking, + AwaitingPublishing, + FailedPublishing, + Cooking, + Cooked, + UnderManualReview, + ScanningForMalware, + ProcessingFile, + PendingRelease, + ReadyForCooking, + PostProcessing +} diff --git a/MinecraftLaunch.Base/Enums/DependencyType.cs b/MinecraftLaunch.Base/Enums/DependencyType.cs new file mode 100644 index 0000000..569b275 --- /dev/null +++ b/MinecraftLaunch.Base/Enums/DependencyType.cs @@ -0,0 +1,10 @@ + +namespace MinecraftLaunch.Base.Enums; + +public enum DependencyType +{ + Required, + Optional, + Incompatible, + Embedded +} diff --git a/MinecraftLaunch.Base/Enums/FileRelationType.cs b/MinecraftLaunch.Base/Enums/FileRelationType.cs new file mode 100644 index 0000000..09036c5 --- /dev/null +++ b/MinecraftLaunch.Base/Enums/FileRelationType.cs @@ -0,0 +1,12 @@ + +namespace MinecraftLaunch.Base.Enums; + +public enum FileRelationType +{ + EmbeddedLibrary = 1, + OptionalDependency, + RequiredDependency, + Tool, + Incompatible, + Include +} diff --git a/MinecraftLaunch.Base/Enums/FileReleaseType.cs b/MinecraftLaunch.Base/Enums/FileReleaseType.cs new file mode 100644 index 0000000..05fa9bf --- /dev/null +++ b/MinecraftLaunch.Base/Enums/FileReleaseType.cs @@ -0,0 +1,9 @@ + +namespace MinecraftLaunch.Base.Enums; + +public enum FileReleaseType +{ + Release = 1, + Beta, + Alpha +} diff --git a/MinecraftLaunch.Base/Enums/HashAlgo.cs b/MinecraftLaunch.Base/Enums/HashAlgo.cs new file mode 100644 index 0000000..f98a550 --- /dev/null +++ b/MinecraftLaunch.Base/Enums/HashAlgo.cs @@ -0,0 +1,7 @@ +namespace MinecraftLaunch.Base.Enums; + +public enum HashAlgo +{ + Sha1 = 1, + Md5 = 2 +} diff --git a/MinecraftLaunch.Base/Enums/ModrinthFileStatus.cs b/MinecraftLaunch.Base/Enums/ModrinthFileStatus.cs new file mode 100644 index 0000000..8a46f46 --- /dev/null +++ b/MinecraftLaunch.Base/Enums/ModrinthFileStatus.cs @@ -0,0 +1,12 @@ + +namespace MinecraftLaunch.Base.Enums; + +public enum ModrinthFileStatus +{ + Listed, + Archived, + Draft, + Unlisted, + Scheduled, + Unknown +} diff --git a/MinecraftLaunch.Base/Enums/RequestedStatus.cs b/MinecraftLaunch.Base/Enums/RequestedStatus.cs new file mode 100644 index 0000000..1a1783c --- /dev/null +++ b/MinecraftLaunch.Base/Enums/RequestedStatus.cs @@ -0,0 +1,10 @@ + +namespace MinecraftLaunch.Base.Enums; + +public enum RequestedStatus +{ + Listed, + Archived, + Draft, + Unlisted +} diff --git a/MinecraftLaunch.Base/Models/Network/CurseForgeFileDependency.cs b/MinecraftLaunch.Base/Models/Network/CurseForgeFileDependency.cs new file mode 100644 index 0000000..ca71a29 --- /dev/null +++ b/MinecraftLaunch.Base/Models/Network/CurseForgeFileDependency.cs @@ -0,0 +1,9 @@ +using MinecraftLaunch.Base.Enums; + +namespace MinecraftLaunch.Base.Models.Network; + +public record CurseForgeFileDependency +{ + public required int ModId { get; init; } + public required FileRelationType RelationType { get; init; } +} diff --git a/MinecraftLaunch.Base/Models/Network/CurseforgeResource.cs b/MinecraftLaunch.Base/Models/Network/CurseforgeResource.cs index 3d5e265..5250963 100644 --- a/MinecraftLaunch.Base/Models/Network/CurseforgeResource.cs +++ b/MinecraftLaunch.Base/Models/Network/CurseforgeResource.cs @@ -1,4 +1,5 @@ -using MinecraftLaunch.Base.Interfaces; +using MinecraftLaunch.Base.Enums; +using MinecraftLaunch.Base.Interfaces; namespace MinecraftLaunch.Base.Models.Network; @@ -20,15 +21,30 @@ public record CurseforgeResource : IResource { public record CurseforgeResourceFile { public required int Id { get; init; } + public required int GameId { get; init; } public required int ModId { get; init; } - public required int ReleaseType { get; init; } - public required uint FileFingerprint { get; init; } - public required bool IsAvailable { get; init; } - public required string FileName { get; init; } + public bool IsAvailable { get; init; } public required string DisplayName { get; init; } + public required string FileName { get; init; } + public required FileReleaseType ReleaseType { get; init; } + public required CurseForgeFileStatus FileStatus { get; init; } + public required IEnumerable Hashes { get; init; } + public required DateTime FileDate { get; init; } + public required long FileLength { get; init; } + public required long DownloadCount { get; init; } + public required long? FileSizeOnDisk { get; init; } public required string DownloadUrl { get; init; } - public required DateTime Published { get; init; } - public required IEnumerable MinecraftVersions { get; init; } - - public bool IsReleased => ReleaseType is 1; + public required IEnumerable GameVersions { get; init; } + public required IEnumerable SortableGameVersions { get; init; } + public required IEnumerable Dependencies { get; init; } + public required bool? ExposeAsAlternative { get; init; } + public required int? ParentProjectFileId { get; init; } + public required int? AlternateFileId { get; init; } + public required bool? IsServerPack { get; init; } + public required int? ServerPackFileId { get; init; } + public required bool? IsEarlyAccessContent { get; init; } + public required DateTime? EarlyAccessEndDate { get; init; } + public required long FileFingerprint { get; init; } + public required IEnumerable Modules { get; init; } + } \ No newline at end of file diff --git a/MinecraftLaunch.Base/Models/Network/FileHash.cs b/MinecraftLaunch.Base/Models/Network/FileHash.cs new file mode 100644 index 0000000..6b6bbfb --- /dev/null +++ b/MinecraftLaunch.Base/Models/Network/FileHash.cs @@ -0,0 +1,9 @@ +using MinecraftLaunch.Base.Enums; + +namespace MinecraftLaunch.Base.Models.Network; + +public record FileHash +{ + public required string Value { get; init; } + public required HashAlgo Algo { get; init; } +} diff --git a/MinecraftLaunch.Base/Models/Network/FileHashes.cs b/MinecraftLaunch.Base/Models/Network/FileHashes.cs new file mode 100644 index 0000000..7acf092 --- /dev/null +++ b/MinecraftLaunch.Base/Models/Network/FileHashes.cs @@ -0,0 +1,8 @@ + +namespace MinecraftLaunch.Base.Models.Network; + +public record FileHashes +{ + public required string Sha512 { get; init; } + public required string Sha1 { get; init; } +} diff --git a/MinecraftLaunch.Base/Models/Network/FileModule.cs b/MinecraftLaunch.Base/Models/Network/FileModule.cs new file mode 100644 index 0000000..b21c19f --- /dev/null +++ b/MinecraftLaunch.Base/Models/Network/FileModule.cs @@ -0,0 +1,8 @@ + +namespace MinecraftLaunch.Base.Models.Network; + +public record FileModule +{ + public required string Name { get; init; } + public required long Fingerprint { get; init; } +} diff --git a/MinecraftLaunch.Base/Models/Network/ModrinthFileDependency.cs b/MinecraftLaunch.Base/Models/Network/ModrinthFileDependency.cs new file mode 100644 index 0000000..8c82199 --- /dev/null +++ b/MinecraftLaunch.Base/Models/Network/ModrinthFileDependency.cs @@ -0,0 +1,12 @@ + +using MinecraftLaunch.Base.Enums; + +namespace MinecraftLaunch.Base.Models.Network; + +public record ModrinthFileDependency +{ + public required DependencyType DependencyType { get; init; } + public string VersionId { get; init; } + public string ProjectId { get; init; } + public string FileName { get; init; } +} diff --git a/MinecraftLaunch.Base/Models/Network/ModrinthResource.cs b/MinecraftLaunch.Base/Models/Network/ModrinthResource.cs index c79dd9d..7b9413c 100644 --- a/MinecraftLaunch.Base/Models/Network/ModrinthResource.cs +++ b/MinecraftLaunch.Base/Models/Network/ModrinthResource.cs @@ -1,4 +1,5 @@ -using MinecraftLaunch.Base.Interfaces; +using MinecraftLaunch.Base.Enums; +using MinecraftLaunch.Base.Interfaces; namespace MinecraftLaunch.Base.Models.Network; @@ -23,25 +24,30 @@ public record ModrinthResource : IResource { } public record ModrinthResourceFiles { - public string Id { get; set; } - public string ChangeLog { get; set; } - public string SourceHash { get; set; } - - public bool IsFeatured { get; set; } - - public int DownloadCount { get; set; } - - public DateTime Published { get; set; } - public IEnumerable Files { get; set; } + public required string Id { get; init; } + public required string ProjectId { get; init; } + public required string AuthorId { get; init; } + public required DateTime DatePublished { get; init; } + public required int Downloads { get; init; } + public required IEnumerable Files { get; init; } + public string ChangelogUrl { get; init; } + public string Name { get; init; } + public string VersionNumber { get; init; } + public string Changelog { get; init; } + public IEnumerable Dependencies { get; init; } + public IEnumerable GameVersions { get; init; } + public FileReleaseType VersionType { get; init; } + public IEnumerable Loaders { get; init; } + public bool Featured { get; init; } + public ModrinthFileStatus Status { get; init; } + public RequestedStatus? RequestedStatus { get; init; } } public record ModrinthResourceFile { - public string Sha1 { get; set; } - public string Sha512 { get; set; } - public string FileName { get; set; } - public string DownloadUrl { get; set; } - - public bool IsPrimary { get; set; } - - public long FileSize { get; set; } + public required FileHashes Hashes { get; init; } + public required string Url { get; init; } + public required string FileName { get; init; } + public required bool Primary { get; init; } + public int Size { get; init; } + public AdditionalFileType? FileType { get; init; } } \ No newline at end of file diff --git a/MinecraftLaunch.Base/Models/Network/SortableGameVersion.cs b/MinecraftLaunch.Base/Models/Network/SortableGameVersion.cs new file mode 100644 index 0000000..a9eab59 --- /dev/null +++ b/MinecraftLaunch.Base/Models/Network/SortableGameVersion.cs @@ -0,0 +1,10 @@ +namespace MinecraftLaunch.Base.Models.Network; + +public record SortableGameVersion +{ + public required string GameVersionName { get; init; } + public required string GameVersionPadded { get; init; } + public required string GameVersion { get; init; } + public required DateTime GameVersionReleaseDate { get; init; } + public required int? GameVersionTypeId { get; init; } +} diff --git a/MinecraftLaunch.Example/Program.cs b/MinecraftLaunch.Example/Program.cs index 9177d1d..2cd7b0b 100644 --- a/MinecraftLaunch.Example/Program.cs +++ b/MinecraftLaunch.Example/Program.cs @@ -178,7 +178,8 @@ #region Curseforge API //CurseforgeProvider curseforgeProvider = new(); -//var options = new CurseforgeSearchOptions { +//var options = new CurseforgeSearchOptions +//{ // SearchFilter = "JEI", // SortOrder = SortOrder.Desc, // SortField = SortField.TotalDownloads @@ -200,19 +201,20 @@ // Console.WriteLine("LatestFiles - FileName: " + string.Join(',', cfResource.LatestFiles.Select(x => x.FileName))); //} -//foreach (var cfResources in await curseforgeProvider.GetResourceFilesByFingerprintsAsync([568671043])) { +//foreach (var cfResources in await curseforgeProvider.GetResourceFilesByFingerprintsAsync([568671043])) +//{ // var cfResource = cfResources.Key; -// Console.WriteLine("Id: " + cfResource.Id); -// Console.WriteLine("ModId: " + cfResource.ModId); -// Console.WriteLine("FileName: " + cfResource.FileName); -// Console.WriteLine("Published: " + cfResource.Published); -// Console.WriteLine("IsAvailable: " + cfResource.IsAvailable); -// Console.WriteLine("ReleaseType: " + cfResource.ReleaseType); -// Console.WriteLine("DownloadUrl: " + cfResource.DownloadUrl); -// Console.WriteLine("FileFingerprint: " + cfResource.FileFingerprint); -// Console.WriteLine("MinecraftVersions: " + string.Join(',', cfResource.MinecraftVersions)); -// Console.WriteLine(); +// //Console.WriteLine("Id: " + cfResource.Id); +// //Console.WriteLine("ModId: " + cfResource.ModId); +// //Console.WriteLine("FileName: " + cfResource.FileName); +// //Console.WriteLine("Published: " + cfResource.Published); +// //Console.WriteLine("IsAvailable: " + cfResource.IsAvailable); +// //Console.WriteLine("ReleaseType: " + cfResource.ReleaseType); +// //Console.WriteLine("DownloadUrl: " + cfResource.DownloadUrl); +// //Console.WriteLine("FileFingerprint: " + cfResource.FileFingerprint); +// //Console.WriteLine("MinecraftVersions: " + string.Join(',', cfResource.MinecraftVersions)); +// //Console.WriteLine(); //} #endregion diff --git a/MinecraftLaunch/Components/Provider/CurseforgeProvider.cs b/MinecraftLaunch/Components/Provider/CurseforgeProvider.cs index 8f16287..3fd40dd 100644 --- a/MinecraftLaunch/Components/Provider/CurseforgeProvider.cs +++ b/MinecraftLaunch/Components/Provider/CurseforgeProvider.cs @@ -218,15 +218,55 @@ private static CurseforgeResourceFile ParseFile(JsonNode node) { return new CurseforgeResourceFile { Id = node.GetInt32("id"), + GameId = node.GetInt32("gameId"), ModId = node.GetInt32("modId"), - FileName = node.GetString("fileName"), - Published = node.GetDateTime("fileDate"), IsAvailable = node.GetBool("isAvailable"), - ReleaseType = node.GetInt32("releaseType"), DisplayName = node.GetString("displayName"), + FileName = node.GetString("fileName"), + ReleaseType = (FileReleaseType)node.GetInt32("releaseType"), + FileStatus = (CurseForgeFileStatus)node.GetInt32("fileStatus"), + Hashes = node.GetEnumerable("hashes").Select(j => new FileHash() + { + Value = j.GetString("value"), + Algo = j.GetInt32("algo") switch + { + 1 => HashAlgo.Sha1, + 2 => HashAlgo.Md5, + _ => throw new NotImplementedException() + } + }), + FileDate = node.GetDateTime("fileDate"), + FileLength = node.GetInt64("fileLength").Value, + DownloadCount = node.GetInt64("downloadCount").Value, + FileSizeOnDisk = node.GetInt64("fileSizeOnDisk"), DownloadUrl = node.GetString("downloadUrl"), - FileFingerprint = node.GetUInt32("fileFingerprint"), - MinecraftVersions = node.GetEnumerable("gameVersions") + GameVersions = node.GetEnumerable("gameVersions"), + SortableGameVersions = node.GetEnumerable("sortableGameVersions").Select(j => new SortableGameVersion() + { + GameVersionName = j.GetString("gameVersionName"), + GameVersionPadded = j.GetString("gameVersionPadded"), + GameVersion = j.GetString("gameVersion"), + GameVersionReleaseDate = j.GetDateTime("gameVersionReleaseDate"), + GameVersionTypeId = j.GetValueOrDefault("gameVersionTypeId") + }), + Dependencies = node.GetEnumerable("dependencies").Select(j => new CurseForgeFileDependency() + { + ModId = j.GetInt32("modId"), + RelationType = (FileRelationType)j.GetInt32("relationType") + }), + ExposeAsAlternative = node.GetValueOrDefault("exposeAsAlternative"), + ParentProjectFileId = node.GetValueOrDefault("parentProjectFileId"), + AlternateFileId = node.GetValueOrDefault("alternateFileId"), + IsServerPack = node.GetValueOrDefault("isServerPack"), + ServerPackFileId = node.GetValueOrDefault("serverPackFileId"), + IsEarlyAccessContent = node.GetValueOrDefault("isEarlyAccessContent"), + EarlyAccessEndDate = node.GetValueOrDefault("earlyAccessEndDate"), + FileFingerprint = node.GetInt64("fileFingerprint").Value, + Modules = node.GetEnumerable("modules").Select(j => new FileModule() + { + Name = j.GetString("name"), + Fingerprint = j.GetInt64("fingerprint").Value + }) }; } diff --git a/MinecraftLaunch/Components/Provider/ModrinthProvider.cs b/MinecraftLaunch/Components/Provider/ModrinthProvider.cs index 007351a..c69856f 100644 --- a/MinecraftLaunch/Components/Provider/ModrinthProvider.cs +++ b/MinecraftLaunch/Components/Provider/ModrinthProvider.cs @@ -4,7 +4,7 @@ using MinecraftLaunch.Base.Models.Network; using MinecraftLaunch.Extensions; using MinecraftLaunch.Utilities; -using System.Linq; +using System.Collections.Generic; using System.Net.Http.Json; using System.Text; using System.Text.Json.Nodes; @@ -187,20 +187,75 @@ private static ModrinthResourceFiles ParseFile(JsonNode node) { if (node == null) return null; return new ModrinthResourceFiles { - Id = node.GetString("project_id"), - SourceHash = node.GetPropertyName(), - IsFeatured = node.GetBool("featured"), - ChangeLog = node.GetString("changelog"), - DownloadCount = node.GetInt32("downloads"), - Published = node.GetDateTime("date_published"), - Files = node.GetEnumerable("files").Select(x => new ModrinthResourceFile { - FileSize = x.GetInt64("size").Value, - DownloadUrl = x.GetString("url"), - IsPrimary = x.GetBool("primary"), - FileName = x.GetString("filename"), - Sha1 = x.Select("hashes").GetString("sha1"), - Sha512 = x.Select("hashes").GetString("sha512"), - }).Where(x => x.IsPrimary) + Id = node.GetString("id"), + ProjectId = node.GetString("project_id"), + AuthorId = node.GetString("author_id"), + DatePublished = node.GetDateTime("date_published"), + Downloads = node.GetInt32("downloads"), + ChangelogUrl = node.GetString("changelog_url"), + Files = node.GetEnumerable("files").Select(j => new ModrinthResourceFile() + { + Hashes = new FileHashes() + { + Sha512 = j["hashes"].GetString("sha512"), + Sha1 = j["hashes"].GetString("sha1") + }, + Url = j.GetString("url"), + FileName = j.GetString("filename"), + Primary = j.GetBool("primary"), + Size = j.GetInt32("size"), + FileType = j.GetString("file_type") switch + { + "required-resource-pack" => AdditionalFileType.RequiredResourcePack, + "optional-resource-pack" => AdditionalFileType.OptionalResourcePack, + _ => throw new NotImplementedException() + } + }), + Name = node.GetString("name"), + VersionNumber = node.GetString("version_number"), + Changelog = node.GetString("changelog"), + Dependencies = node.GetEnumerable("dependencies").Select(j => new ModrinthFileDependency() + { + DependencyType = j.GetString("dependency_type") switch + { + "required" => DependencyType.Required, + "optional" => DependencyType.Optional, + "incompatible" => DependencyType.Incompatible, + "embedded" => DependencyType.Embedded, + _ => throw new NotImplementedException() + }, + VersionId = j.GetString("version_id"), + ProjectId = j.GetString("project_id"), + FileName = j.GetString("file_name") + }), + GameVersions = node.GetEnumerable("game_versions"), + VersionType = node.GetString("version_type") switch + { + "release" => FileReleaseType.Release, + "beta" => FileReleaseType.Beta, + "alpha" => FileReleaseType.Alpha, + _ => throw new NotImplementedException() + }, + Loaders = node.GetEnumerable("loaders"), + Featured = node.GetBool("featured"), + Status = node.GetString("status") switch + { + "listed" => ModrinthFileStatus.Listed, + "archived" => ModrinthFileStatus.Archived, + "draft" => ModrinthFileStatus.Draft, + "unlisted" => ModrinthFileStatus.Unlisted, + "scheduled" => ModrinthFileStatus.Scheduled, + "unknown" => ModrinthFileStatus.Unknown, + _ => throw new NotImplementedException() + }, + RequestedStatus = node.GetString("requested_status") switch + { + "listed" => RequestedStatus.Listed, + "archived" => RequestedStatus.Archived, + "draft" => RequestedStatus.Draft, + "unlisted" => RequestedStatus.Unlisted, + _ => null + } }; } diff --git a/MinecraftLaunch/Extensions/JsonNodeExtension.cs b/MinecraftLaunch/Extensions/JsonNodeExtension.cs index 9d7210a..c38836d 100644 --- a/MinecraftLaunch/Extensions/JsonNodeExtension.cs +++ b/MinecraftLaunch/Extensions/JsonNodeExtension.cs @@ -6,6 +6,12 @@ namespace MinecraftLaunch.Extensions; public static partial class JsonNodeExtension { + public static TValue? GetValueOrDefault(this JsonNode node, string propertyName) where TValue : struct + { + _ = node.TryGetValue(propertyName, out var value); + return value; + } + public static string FixJson(this string errorJson) => errorJson .FixJsonStringNewlines() .FixDuplicateEmptyKeys();