diff --git a/Wabbajack.Lib/AInstaller.cs b/Wabbajack.Lib/AInstaller.cs index e53ec1e4..37bb8147 100644 --- a/Wabbajack.Lib/AInstaller.cs +++ b/Wabbajack.Lib/AInstaller.cs @@ -195,6 +195,12 @@ namespace Wabbajack.Lib await Task.WhenAll(dispatchers.Select(d => d.Prepare())); + var nexusDownloader = dispatchers.OfType().FirstOrDefault(); + if (nexusDownloader != null && !await nexusDownloader.HaveEnoughAPICalls(missing)) + { + throw new Exception($"Not enough Nexus API calls to download this list, please try again after midnight GMT when your API limits reset"); + } + await DownloadMissingArchives(missing); } @@ -210,6 +216,7 @@ namespace Wabbajack.Lib } DesiredThreads.OnNext(DownloadThreads); + await missing.Where(a => a.State.GetType() != typeof(ManualDownloader.State)) .PMap(Queue, UpdateTracker, async archive => { diff --git a/Wabbajack.Lib/Downloaders/NexusDownloader.cs b/Wabbajack.Lib/Downloaders/NexusDownloader.cs index 1967584f..8fcd50b2 100644 --- a/Wabbajack.Lib/Downloaders/NexusDownloader.cs +++ b/Wabbajack.Lib/Downloaders/NexusDownloader.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reactive; @@ -142,6 +143,16 @@ namespace Wabbajack.Lib.Downloaders } } + public async Task HaveEnoughAPICalls(IEnumerable archives) + { + if (await Client!.IsPremium()) + return true; + + var count = archives.Select(a => a.State).OfType().Count(); + + return count < Client!.RemainingAPICalls; + } + [JsonName("NexusDownloader")] public class State : AbstractDownloadState, IMetaState, IUpgradingState { @@ -191,12 +202,9 @@ namespace Wabbajack.Lib.Downloaders } catch (Exception ex) { - Utils.Log($"{a.Name} - Error getting Nexus download URL - {ex.Message}"); return false; } - Utils.Log($"Downloading Nexus Archive - {a.Name} - {Game} - {ModID} - {FileID}"); - return await new HTTPDownloader.State(url).Download(a, destination); } diff --git a/Wabbajack.Lib/NexusApi/INexusApi.cs b/Wabbajack.Lib/NexusApi/INexusApi.cs index e6bb9efd..a6d60907 100644 --- a/Wabbajack.Lib/NexusApi/INexusApi.cs +++ b/Wabbajack.Lib/NexusApi/INexusApi.cs @@ -13,5 +13,7 @@ namespace Wabbajack.Lib.NexusApi public Task GetUserStatus(); public Task IsPremium(); public bool IsAuthenticated { get; } + + public int RemainingAPICalls { get; } } } diff --git a/Wabbajack.Lib/NexusApi/NexusApi.cs b/Wabbajack.Lib/NexusApi/NexusApi.cs index c2be42d9..bf7a0e02 100644 --- a/Wabbajack.Lib/NexusApi/NexusApi.cs +++ b/Wabbajack.Lib/NexusApi/NexusApi.cs @@ -27,6 +27,7 @@ namespace Wabbajack.Lib.NexusApi public static string? ApiKey { get; set; } public bool IsAuthenticated => ApiKey != null; + public int RemainingAPICalls => Math.Max(HourlyRemaining, DailyRemaining); private Task? _userStatus; public Task UserStatus @@ -213,24 +214,12 @@ namespace Wabbajack.Lib.NexusApi } - protected virtual async Task UpdateRemaining(HttpResponseMessage response) { try { - var oldDaily = _dailyRemaining; - var oldHourly = _hourlyRemaining; - var dailyRemaining = int.Parse(response.Headers.GetValues("x-rl-daily-remaining").First()); - var hourlyRemaining = int.Parse(response.Headers.GetValues("x-rl-hourly-remaining").First()); - - lock (RemainingLock) - { - _dailyRemaining = Math.Min(_dailyRemaining, dailyRemaining); - _hourlyRemaining = Math.Min(_hourlyRemaining, hourlyRemaining); - } - - if (oldDaily != _dailyRemaining || oldHourly != _hourlyRemaining) - Utils.Log($"Nexus requests remaining: {_dailyRemaining} daily - {_hourlyRemaining} hourly"); + _dailyRemaining = int.Parse(response.Headers.GetValues("x-rl-daily-remaining").First()); + _hourlyRemaining = int.Parse(response.Headers.GetValues("x-rl-hourly-remaining").First()); this.RaisePropertyChanged(nameof(DailyRemaining)); this.RaisePropertyChanged(nameof(HourlyRemaining)); @@ -317,20 +306,17 @@ namespace Wabbajack.Lib.NexusApi var info = await GetModInfo(archive.Game, archive.ModID); if (!info.available) throw new Exception("Mod unavailable"); - - var url = $"https://api.nexusmods.com/v1/games/{archive.Game.MetaData().NexusName}/mods/{archive.ModID}/files/{archive.FileID}/download_link.json"; - try - { - return (await Get>(url)).First().URI; - } - catch (HttpException ex) - { - - if (ex.Code != 403 || await IsPremium()) + if (await IsPremium()) + { + if (HourlyRemaining <= 0 && DailyRemaining <= 0) { - throw; + throw new Exception($"You have run out of Nexus API requests, please try again after midnight GMT when the API limits reset"); } + + var url = + $"https://api.nexusmods.com/v1/games/{archive.Game.MetaData().NexusName}/mods/{archive.ModID}/files/{archive.FileID}/download_link.json"; + return (await Get>(url)).First().URI; } try