mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Add non-Nexus mods to the Slideshow (#574)
* Created AbstractMetaState * Added IAbstractMetaState to NexusDownloader.State Slideshow is fully working with this setup and nothing changed functionally. * Renamed IAbstractMetaState to IMetaState * Changed modVMs in SlideShow from type NexusDownloader.State to IMetaState * Simplified IMetaState and ModVM * Removed Setter from IMetaState and added to LoversLabDownloader * Throw exception when the modlist could not be loaded * Created AbstractMetaState AbstractMetaState implements AbstractDownloadState and indicates that a State from a specific Download contains meta information. This is used for the Slideshow and can also be used for the Manifest. * Created GatherMetaData function * Implemented new AbstractMetaState for LoversLab * Implemented new AbstractMetaState for NexusMods * Replaced Utils.Log with Utils.Error * Slideshow fixes * Replaced AbstractMetaState with IMetaState * Updated CHANGELOG Co-authored-by: Timothy Baldridge <tbaldridge@gmail.com>
This commit is contained in:
parent
a1e911669a
commit
1ce640ba2b
@ -1,5 +1,9 @@
|
|||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
|
#### Version - 1.0.1.0 - 3/xx/2020
|
||||||
|
* Added download support for YouTube
|
||||||
|
* Slideshow can now display mods from non-Nexus sites
|
||||||
|
|
||||||
#### Verison - 1.0.0.0 - 2/29/2020
|
#### Verison - 1.0.0.0 - 2/29/2020
|
||||||
* 1.0, first non-beta release
|
* 1.0, first non-beta release
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ namespace Wabbajack.Common
|
|||||||
|
|
||||||
return sha.Hash.ToBase64();
|
return sha.Hash.ToBase64();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string StringSHA256Hex(this string s)
|
public static string StringSHA256Hex(this string s)
|
||||||
{
|
{
|
||||||
var sha = new SHA256Managed();
|
var sha = new SHA256Managed();
|
||||||
|
@ -78,6 +78,27 @@ namespace Wabbajack.Lib
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> GatherMetaData()
|
||||||
|
{
|
||||||
|
Utils.Log($"Getting meta data for {SelectedArchives.Count} archives");
|
||||||
|
await SelectedArchives.PMap(Queue, async a =>
|
||||||
|
{
|
||||||
|
if (a.State is IMetaState metaState)
|
||||||
|
{
|
||||||
|
var b = await metaState.LoadMetaData();
|
||||||
|
Utils.Log(b
|
||||||
|
? $"Getting meta data for {a.Name} was successful!"
|
||||||
|
: $"Getting meta data for {a.Name} failed!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Utils.Log($"Archive {a.Name} is not an AbstractMetaState!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void ExportModList()
|
public void ExportModList()
|
||||||
{
|
{
|
||||||
Utils.Log($"Exporting ModList to {ModListOutputFile}");
|
Utils.Log($"Exporting ModList to {ModListOutputFile}");
|
||||||
|
@ -30,7 +30,7 @@ namespace Wabbajack.Lib
|
|||||||
typeof(PropertyFile), typeof(SteamMeta), typeof(SteamWorkshopDownloader), typeof(SteamWorkshopDownloader.State),
|
typeof(PropertyFile), typeof(SteamMeta), typeof(SteamWorkshopDownloader), typeof(SteamWorkshopDownloader.State),
|
||||||
typeof(LoversLabDownloader.State), typeof(GameFileSourceDownloader.State), typeof(VectorPlexusDownloader.State),
|
typeof(LoversLabDownloader.State), typeof(GameFileSourceDownloader.State), typeof(VectorPlexusDownloader.State),
|
||||||
typeof(DeadlyStreamDownloader.State), typeof(AFKModsDownloader.State), typeof(TESAllianceDownloader.State),
|
typeof(DeadlyStreamDownloader.State), typeof(AFKModsDownloader.State), typeof(TESAllianceDownloader.State),
|
||||||
typeof(TES3ArchiveState), typeof(TES3FileState), typeof(BethesdaNetDownloader.State), typeof(YouTubeDownloader)
|
typeof(TES3ArchiveState), typeof(TES3FileState), typeof(BethesdaNetDownloader.State), typeof(YouTubeDownloader), typeof(IMetaState)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Config.VersionTolerance.Mode = VersionToleranceMode.Standard;
|
Config.VersionTolerance.Mode = VersionToleranceMode.Standard;
|
||||||
|
@ -7,10 +7,23 @@ using Wabbajack.Lib.Validation;
|
|||||||
|
|
||||||
namespace Wabbajack.Lib.Downloaders
|
namespace Wabbajack.Lib.Downloaders
|
||||||
{
|
{
|
||||||
|
public interface IMetaState
|
||||||
|
{
|
||||||
|
string URL { get; }
|
||||||
|
string Name { get; set; }
|
||||||
|
string Author { get; set; }
|
||||||
|
string Version { get; set; }
|
||||||
|
string ImageURL { get; set; }
|
||||||
|
bool IsNSFW { get; set; }
|
||||||
|
string Description { get; set; }
|
||||||
|
|
||||||
|
Task<bool> LoadMetaData();
|
||||||
|
}
|
||||||
|
|
||||||
public abstract class AbstractDownloadState
|
public abstract class AbstractDownloadState
|
||||||
{
|
{
|
||||||
|
|
||||||
public static List<Type> KnownSubTypes = new List<Type>()
|
public static List<Type> KnownSubTypes = new List<Type>
|
||||||
{
|
{
|
||||||
typeof(HTTPDownloader.State),
|
typeof(HTTPDownloader.State),
|
||||||
typeof(GameFileSourceDownloader.State),
|
typeof(GameFileSourceDownloader.State),
|
||||||
|
@ -5,6 +5,7 @@ using System.Net;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
|
using HtmlAgilityPack;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.Lib.Validation;
|
using Wabbajack.Lib.Validation;
|
||||||
@ -15,8 +16,8 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
// IPS4 is the site used by LoversLab, VectorPlexus, etc. the general mechanics of each site are the
|
// IPS4 is the site used by LoversLab, VectorPlexus, etc. the general mechanics of each site are the
|
||||||
// same, so we can fairly easily abstract the state.
|
// same, so we can fairly easily abstract the state.
|
||||||
// Pass in the state type via TState
|
// Pass in the state type via TState
|
||||||
public abstract class AbstractIPS4Downloader<TDownloader, TState> : AbstractNeedsLoginDownloader, IDownloader
|
public abstract class AbstractIPS4Downloader<TDownloader, TState> : AbstractNeedsLoginDownloader, IDownloader
|
||||||
where TState : AbstractIPS4Downloader<TDownloader, TState>.State<TDownloader>, new()
|
where TState : AbstractIPS4Downloader<TDownloader, TState>.State<TDownloader>, new()
|
||||||
where TDownloader : IDownloader
|
where TDownloader : IDownloader
|
||||||
{
|
{
|
||||||
public override string SiteName { get; }
|
public override string SiteName { get; }
|
||||||
@ -61,7 +62,7 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class State<TDownloader> : AbstractDownloadState where TDownloader : IDownloader
|
public class State<TDownloader> : AbstractDownloadState, IMetaState where TDownloader : IDownloader
|
||||||
{
|
{
|
||||||
public string FileID { get; set; }
|
public string FileID { get; set; }
|
||||||
public string FileName { get; set; }
|
public string FileName { get; set; }
|
||||||
@ -69,10 +70,12 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
private static bool IsHTTPS => Downloader.SiteURL.AbsolutePath.StartsWith("https://");
|
private static bool IsHTTPS => Downloader.SiteURL.AbsolutePath.StartsWith("https://");
|
||||||
private static string URLPrefix => IsHTTPS ? "https://" : "http://";
|
private static string URLPrefix => IsHTTPS ? "https://" : "http://";
|
||||||
|
|
||||||
private static string Site => string.IsNullOrWhiteSpace(Downloader.SiteURL.Query)
|
public static string Site => string.IsNullOrWhiteSpace(Downloader.SiteURL.Query)
|
||||||
? $"{URLPrefix}{Downloader.SiteURL.Host}"
|
? $"{URLPrefix}{Downloader.SiteURL.Host}"
|
||||||
: Downloader.SiteURL.ToString();
|
: Downloader.SiteURL.ToString();
|
||||||
|
|
||||||
|
public static AbstractNeedsLoginDownloader Downloader => (AbstractNeedsLoginDownloader)(object)DownloadDispatcher.GetInstance<TDownloader>();
|
||||||
|
|
||||||
public override object[] PrimaryKey
|
public override object[] PrimaryKey
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -100,13 +103,13 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
|
|
||||||
private async Task<Stream> ResolveDownloadStream()
|
private async Task<Stream> ResolveDownloadStream()
|
||||||
{
|
{
|
||||||
var downloader = (AbstractNeedsLoginDownloader)(object)DownloadDispatcher.GetInstance<TDownloader>();
|
//var downloader = (AbstractNeedsLoginDownloader)(object)DownloadDispatcher.GetInstance<TDownloader>();
|
||||||
|
|
||||||
TOP:
|
TOP:
|
||||||
var csrfurl = FileID == null
|
var csrfurl = FileID == null
|
||||||
? $"{Site}/files/file/{FileName}/?do=download"
|
? $"{Site}/files/file/{FileName}/?do=download"
|
||||||
: $"{Site}/files/file/{FileName}/?do=download&r={FileID}";
|
: $"{Site}/files/file/{FileName}/?do=download&r={FileID}";
|
||||||
var html = await downloader.AuthedClient.GetStringAsync(csrfurl);
|
var html = await Downloader.AuthedClient.GetStringAsync(csrfurl);
|
||||||
|
|
||||||
var pattern = new Regex("(?<=csrfKey=).*(?=[&\"\'])|(?<=csrfKey: \").*(?=[&\"\'])");
|
var pattern = new Regex("(?<=csrfKey=).*(?=[&\"\'])|(?<=csrfKey: \").*(?=[&\"\'])");
|
||||||
var matches = pattern.Matches(html).Cast<Match>();
|
var matches = pattern.Matches(html).Cast<Match>();
|
||||||
@ -122,10 +125,10 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
: $"{Site}/files/file/{FileName}/{sep}do=download&r={FileID}&confirm=1&t=1&csrfKey={csrfKey}";
|
: $"{Site}/files/file/{FileName}/{sep}do=download&r={FileID}&confirm=1&t=1&csrfKey={csrfKey}";
|
||||||
|
|
||||||
|
|
||||||
var streamResult = await downloader.AuthedClient.GetAsync(url);
|
var streamResult = await Downloader.AuthedClient.GetAsync(url);
|
||||||
if (streamResult.StatusCode != HttpStatusCode.OK)
|
if (streamResult.StatusCode != HttpStatusCode.OK)
|
||||||
{
|
{
|
||||||
Utils.ErrorThrow(new InvalidOperationException(), $"{downloader.SiteName} servers reported an error for file: {FileID}");
|
Utils.ErrorThrow(new InvalidOperationException(), $"{Downloader.SiteName} servers reported an error for file: {FileID}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var contentType = streamResult.Content.Headers.ContentType;
|
var contentType = streamResult.Content.Headers.ContentType;
|
||||||
@ -138,7 +141,7 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
var secs = times.Download - times.CurrentTime;
|
var secs = times.Download - times.CurrentTime;
|
||||||
for (int x = 0; x < secs; x++)
|
for (int x = 0; x < secs; x++)
|
||||||
{
|
{
|
||||||
Utils.Status($"Waiting for {secs} at the request of {downloader.SiteName}", Percent.FactoryPutInRange(x, secs));
|
Utils.Status($"Waiting for {secs} at the request of {Downloader.SiteName}", Percent.FactoryPutInRange(x, secs));
|
||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
}
|
}
|
||||||
streamResult.Dispose();
|
streamResult.Dispose();
|
||||||
@ -200,7 +203,19 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AbstractNeedsLoginDownloader Downloader => (AbstractNeedsLoginDownloader)(object)DownloadDispatcher.GetInstance<TDownloader>();
|
// from IMetaState
|
||||||
|
public string URL => $"{Site}/files/file/{FileName}";
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Author { get; set; }
|
||||||
|
public string Version { get; set; }
|
||||||
|
public string ImageURL { get; set; }
|
||||||
|
public virtual bool IsNSFW { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
public virtual async Task<bool> LoadMetaData()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AbstractIPS4Downloader(Uri loginUri, string encryptedKeyName, string cookieDomain) :
|
protected AbstractIPS4Downloader(Uri loginUri, string encryptedKeyName, string cookieDomain) :
|
||||||
|
@ -1,24 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Reactive;
|
|
||||||
using System.Reactive.Linq;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using HtmlAgilityPack;
|
||||||
using System.Windows.Input;
|
|
||||||
using CefSharp;
|
|
||||||
using ReactiveUI;
|
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.Lib.LibCefHelpers;
|
|
||||||
using Wabbajack.Lib.NexusApi;
|
|
||||||
using Wabbajack.Lib.Validation;
|
|
||||||
using Wabbajack.Lib.WebAutomation;
|
using Wabbajack.Lib.WebAutomation;
|
||||||
using File = Alphaleonis.Win32.Filesystem.File;
|
|
||||||
|
|
||||||
namespace Wabbajack.Lib.Downloaders
|
namespace Wabbajack.Lib.Downloaders
|
||||||
{
|
{
|
||||||
@ -29,7 +14,6 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
public override Uri SiteURL => new Uri("https://www.loverslab.com");
|
public override Uri SiteURL => new Uri("https://www.loverslab.com");
|
||||||
public override Uri IconUri => new Uri("https://www.loverslab.com/favicon.ico");
|
public override Uri IconUri => new Uri("https://www.loverslab.com/favicon.ico");
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public LoversLabDownloader() : base(new Uri("https://www.loverslab.com/login"),
|
public LoversLabDownloader() : base(new Uri("https://www.loverslab.com/login"),
|
||||||
"loverslabcookies", "loverslab.com")
|
"loverslabcookies", "loverslab.com")
|
||||||
{
|
{
|
||||||
@ -46,8 +30,31 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
Utils.Error(ex);
|
Utils.Error(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class State : State<LoversLabDownloader>
|
public class State : State<LoversLabDownloader>
|
||||||
{
|
{
|
||||||
|
public override bool IsNSFW => true;
|
||||||
|
|
||||||
|
public override async Task<bool> LoadMetaData()
|
||||||
|
{
|
||||||
|
var html = await Downloader.AuthedClient.GetStringAsync(URL);
|
||||||
|
var doc = new HtmlDocument();
|
||||||
|
doc.LoadHtml(html);
|
||||||
|
var node = doc.DocumentNode;
|
||||||
|
Name = node.SelectNodes("//h1[@class='ipsType_pageTitle ipsContained_container']/span")?.First().InnerHtml;
|
||||||
|
Author = node
|
||||||
|
.SelectNodes(
|
||||||
|
"//div[@class='ipsBox_alt']/div[@class='ipsPhotoPanel ipsPhotoPanel_tiny ipsClearfix ipsSpacer_bottom']/div/p[@class='ipsType_reset ipsType_large ipsType_blendLinks']/a")
|
||||||
|
?.First().InnerHtml;
|
||||||
|
Version = node.SelectNodes("//section/h2[@class='ipsType_sectionHead']/span[@data-role='versionTitle']")
|
||||||
|
?
|
||||||
|
.First().InnerHtml;
|
||||||
|
ImageURL = node
|
||||||
|
.SelectNodes(
|
||||||
|
"//div[@class='ipsBox ipsSpacer_top ipsSpacer_double']/section/div[@class='ipsPad ipsAreaBackground']/div[@class='ipsCarousel ipsClearfix']/div[@class='ipsCarousel_inner']/ul[@class='cDownloadsCarousel ipsClearfix']/li[@class='ipsCarousel_item ipsAreaBackground_reset ipsPad_half']/span[@class='ipsThumb ipsThumb_medium ipsThumb_bg ipsCursor_pointer']")
|
||||||
|
?.First().GetAttributeValue("data-fullurl", "none");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,13 @@ using System.Reactive.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using Ceras;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.Common.StatusFeed.Errors;
|
using Wabbajack.Common.StatusFeed.Errors;
|
||||||
using Wabbajack.Lib.NexusApi;
|
using Wabbajack.Lib.NexusApi;
|
||||||
using Wabbajack.Lib.Validation;
|
using Wabbajack.Lib.Validation;
|
||||||
|
using Game = Wabbajack.Common.Game;
|
||||||
|
|
||||||
namespace Wabbajack.Lib.Downloaders
|
namespace Wabbajack.Lib.Downloaders
|
||||||
{
|
{
|
||||||
@ -69,21 +71,18 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
Utils.Error($"Error getting mod info for Nexus mod with {general.modID}");
|
Utils.Error($"Error getting mod info for Nexus mod with {general.modID}");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new State
|
return new State
|
||||||
{
|
{
|
||||||
GameName = general.gameName,
|
Name = NexusApiUtils.FixupSummary(info.name),
|
||||||
FileID = general.fileID,
|
Author = NexusApiUtils.FixupSummary(info.author),
|
||||||
ModID = general.modID,
|
|
||||||
Version = general.version ?? "0.0.0.0",
|
Version = general.version ?? "0.0.0.0",
|
||||||
Author = info.author,
|
ImageURL = info.picture_url,
|
||||||
UploadedBy = info.uploaded_by,
|
IsNSFW = info.contains_adult_content,
|
||||||
UploaderProfile = info.uploaded_users_profile_url,
|
Description = NexusApiUtils.FixupSummary(info.summary),
|
||||||
ModName = info.name,
|
GameName = general.gameName,
|
||||||
SlideShowPic = info.picture_url,
|
ModID = general.modID,
|
||||||
NexusURL = NexusApiUtils.GetModURL(game, info.mod_id),
|
FileID = general.fileID
|
||||||
Summary = info.summary,
|
|
||||||
Adult = info.contains_adult_content
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,20 +122,30 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class State : AbstractDownloadState
|
public class State : AbstractDownloadState, IMetaState
|
||||||
{
|
{
|
||||||
|
public string URL => $"http://nexusmods.com/{NexusApiUtils.ConvertGameName(GameName)}/mods/{ModID}";
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
public string Author { get; set; }
|
public string Author { get; set; }
|
||||||
public string FileID { get; set; }
|
|
||||||
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
public string ImageURL { get; set; }
|
||||||
|
|
||||||
|
public bool IsNSFW { get; set; }
|
||||||
|
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
public async Task<bool> LoadMetaData()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public string GameName { get; set; }
|
public string GameName { get; set; }
|
||||||
public string ModID { get; set; }
|
public string ModID { get; set; }
|
||||||
public string UploadedBy { get; set; }
|
public string FileID { get; set; }
|
||||||
public string UploaderProfile { get; set; }
|
|
||||||
public string Version { get; set; }
|
|
||||||
public string SlideShowPic { get; set; }
|
|
||||||
public string ModName { get; set; }
|
|
||||||
public string NexusURL { get; set; }
|
|
||||||
public string Summary { get; set; }
|
|
||||||
public bool Adult { get; set; }
|
|
||||||
|
|
||||||
public override object[] PrimaryKey { get => new object[]{GameName, ModID, FileID};}
|
public override object[] PrimaryKey { get => new object[]{GameName, ModID, FileID};}
|
||||||
|
|
||||||
@ -192,7 +201,7 @@ namespace Wabbajack.Lib.Downloaders
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.Log($"{ModName} - {GameName} - {ModID} - {FileID} - Error getting Nexus download URL - {ex}");
|
Utils.Log($"{Name} - {GameName} - {ModID} - {FileID} - Error getting Nexus download URL - {ex}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ namespace Wabbajack.Lib
|
|||||||
protected override async Task<bool> _Begin(CancellationToken cancel)
|
protected override async Task<bool> _Begin(CancellationToken cancel)
|
||||||
{
|
{
|
||||||
if (cancel.IsCancellationRequested) return false;
|
if (cancel.IsCancellationRequested) return false;
|
||||||
ConfigureProcessor(19, ConstructDynamicNumThreads(await RecommendQueueSize()));
|
ConfigureProcessor(20, ConstructDynamicNumThreads(await RecommendQueueSize()));
|
||||||
UpdateTracker.Reset();
|
UpdateTracker.Reset();
|
||||||
UpdateTracker.NextStep("Gathering information");
|
UpdateTracker.NextStep("Gathering information");
|
||||||
Info("Looking for other profiles");
|
Info("Looking for other profiles");
|
||||||
@ -279,6 +279,9 @@ namespace Wabbajack.Lib
|
|||||||
UpdateTracker.NextStep("Building Patches");
|
UpdateTracker.NextStep("Building Patches");
|
||||||
await BuildPatches();
|
await BuildPatches();
|
||||||
|
|
||||||
|
UpdateTracker.NextStep("Gathering Metadata");
|
||||||
|
await GatherMetaData();
|
||||||
|
|
||||||
ModList = new ModList
|
ModList = new ModList
|
||||||
{
|
{
|
||||||
GameType = CompilingGame.Game,
|
GameType = CompilingGame.Game,
|
||||||
|
@ -284,7 +284,7 @@ namespace Wabbajack.Lib.NexusApi
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Utils.Log($"Requesting manual download for {archive.ModName}");
|
Utils.Log($"Requesting manual download for {archive.Name}");
|
||||||
return (await Utils.Log(await ManuallyDownloadNexusFile.Create(archive)).Task).ToString();
|
return (await Utils.Log(await ManuallyDownloadNexusFile.Create(archive)).Task).ToString();
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException ex)
|
catch (TaskCanceledException ex)
|
||||||
|
@ -113,7 +113,7 @@ namespace Wabbajack.Lib.Validation
|
|||||||
if (nexus_mod_permissions.TryGetValue(p.ArchiveHashPath[0], out var archive))
|
if (nexus_mod_permissions.TryGetValue(p.ArchiveHashPath[0], out var archive))
|
||||||
{
|
{
|
||||||
var ext = Path.GetExtension(p.ArchiveHashPath.Last());
|
var ext = Path.GetExtension(p.ArchiveHashPath.Last());
|
||||||
var url = (archive.archive.State as NexusDownloader.State).NexusURL;
|
var url = (archive.archive.State as NexusDownloader.State).URL;
|
||||||
if (Consts.AssetFileExtensions.Contains(ext) && !(archive.permissions.CanModifyAssets ?? true))
|
if (Consts.AssetFileExtensions.Contains(ext) && !(archive.permissions.CanModifyAssets ?? true))
|
||||||
{
|
{
|
||||||
ValidationErrors.Push($"{p.To} from {url} is set to disallow asset modification");
|
ValidationErrors.Push($"{p.To} from {url} is set to disallow asset modification");
|
||||||
@ -131,7 +131,7 @@ namespace Wabbajack.Lib.Validation
|
|||||||
{
|
{
|
||||||
if (nexus_mod_permissions.TryGetValue(p.ArchiveHashPath[0], out var archive))
|
if (nexus_mod_permissions.TryGetValue(p.ArchiveHashPath[0], out var archive))
|
||||||
{
|
{
|
||||||
var url = (archive.archive.State as NexusDownloader.State).NexusURL;
|
var url = (archive.archive.State as NexusDownloader.State).URL;
|
||||||
if (!(archive.permissions.CanExtractBSAs ?? true) &&
|
if (!(archive.permissions.CanExtractBSAs ?? true) &&
|
||||||
p.ArchiveHashPath.Skip(1).ButLast().Any(a => Consts.SupportedBSAs.Contains(Path.GetExtension(a).ToLower())))
|
p.ArchiveHashPath.Skip(1).ButLast().Any(a => Consts.SupportedBSAs.Contains(Path.GetExtension(a).ToLower())))
|
||||||
{
|
{
|
||||||
|
@ -274,7 +274,7 @@ namespace Wabbajack
|
|||||||
_titleText = Observable.CombineLatest(
|
_titleText = Observable.CombineLatest(
|
||||||
this.WhenAny(x => x.ModList)
|
this.WhenAny(x => x.ModList)
|
||||||
.Select(modList => modList?.Name ?? string.Empty),
|
.Select(modList => modList?.Name ?? string.Empty),
|
||||||
this.WhenAny(x => x.Slideshow.TargetMod.ModName)
|
this.WhenAny(x => x.Slideshow.TargetMod.State.Name)
|
||||||
.StartWith(default(string)),
|
.StartWith(default(string)),
|
||||||
this.WhenAny(x => x.Installing),
|
this.WhenAny(x => x.Installing),
|
||||||
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
||||||
@ -282,7 +282,7 @@ namespace Wabbajack
|
|||||||
_authorText = Observable.CombineLatest(
|
_authorText = Observable.CombineLatest(
|
||||||
this.WhenAny(x => x.ModList)
|
this.WhenAny(x => x.ModList)
|
||||||
.Select(modList => modList?.Author ?? string.Empty),
|
.Select(modList => modList?.Author ?? string.Empty),
|
||||||
this.WhenAny(x => x.Slideshow.TargetMod.ModAuthor)
|
this.WhenAny(x => x.Slideshow.TargetMod.State.Author)
|
||||||
.StartWith(default(string)),
|
.StartWith(default(string)),
|
||||||
this.WhenAny(x => x.Installing),
|
this.WhenAny(x => x.Installing),
|
||||||
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
||||||
@ -290,7 +290,7 @@ namespace Wabbajack
|
|||||||
_description = Observable.CombineLatest(
|
_description = Observable.CombineLatest(
|
||||||
this.WhenAny(x => x.ModList)
|
this.WhenAny(x => x.ModList)
|
||||||
.Select(modList => modList?.Description ?? string.Empty),
|
.Select(modList => modList?.Description ?? string.Empty),
|
||||||
this.WhenAny(x => x.Slideshow.TargetMod.ModDescription)
|
this.WhenAny(x => x.Slideshow.TargetMod.State.Description)
|
||||||
.StartWith(default(string)),
|
.StartWith(default(string)),
|
||||||
this.WhenAny(x => x.Installing),
|
this.WhenAny(x => x.Installing),
|
||||||
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
||||||
|
@ -38,6 +38,7 @@ namespace Wabbajack
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Error = ex;
|
Error = ex;
|
||||||
|
Utils.Error(ex, "Exception while loading the modlist!");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageObservable = Observable.Return(Unit.Default)
|
ImageObservable = Observable.Return(Unit.Default)
|
||||||
|
@ -1,49 +1,29 @@
|
|||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.Lib;
|
using Wabbajack.Lib;
|
||||||
using Wabbajack.Lib.Downloaders;
|
using Wabbajack.Lib.Downloaders;
|
||||||
using Wabbajack.Lib.NexusApi;
|
|
||||||
|
|
||||||
namespace Wabbajack
|
namespace Wabbajack
|
||||||
{
|
{
|
||||||
public class ModVM : ViewModel
|
public class ModVM : ViewModel
|
||||||
{
|
{
|
||||||
public string ModName { get; }
|
public IMetaState State { get; }
|
||||||
|
|
||||||
public string ModID { get; }
|
|
||||||
|
|
||||||
public string ModDescription { get; }
|
|
||||||
|
|
||||||
public string ModAuthor { get; }
|
|
||||||
|
|
||||||
public bool IsNSFW { get; }
|
|
||||||
|
|
||||||
public string ModURL { get; }
|
|
||||||
|
|
||||||
public string ImageURL { get; }
|
|
||||||
|
|
||||||
// Image isn't exposed as a direct property, but as an observable.
|
// Image isn't exposed as a direct property, but as an observable.
|
||||||
// This acts as a caching mechanism, as interested parties will trigger it to be created,
|
// This acts as a caching mechanism, as interested parties will trigger it to be created,
|
||||||
// and the cached image will automatically be released when the last interested party is gone.
|
// and the cached image will automatically be released when the last interested party is gone.
|
||||||
public IObservable<BitmapImage> ImageObservable { get; }
|
public IObservable<BitmapImage> ImageObservable { get; }
|
||||||
|
|
||||||
public ModVM(NexusDownloader.State m)
|
public ModVM(IMetaState state)
|
||||||
{
|
{
|
||||||
ModName = NexusApiUtils.FixupSummary(m.ModName);
|
State = state;
|
||||||
ModID = m.ModID;
|
|
||||||
ModDescription = NexusApiUtils.FixupSummary(m.Summary);
|
ImageObservable = Observable.Return(State.ImageURL)
|
||||||
ModAuthor = NexusApiUtils.FixupSummary(m.Author);
|
|
||||||
IsNSFW = m.Adult;
|
|
||||||
ModURL = m.NexusURL;
|
|
||||||
ImageURL = m.SlideShowPic;
|
|
||||||
ImageObservable = Observable.Return(ImageURL)
|
|
||||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||||
.DownloadBitmapImage((ex) => Utils.Log($"Skipping slide for mod {ModName} ({ModID})"))
|
.DownloadBitmapImage((ex) => Utils.Log($"Skipping slide for mod {State.Name}"))
|
||||||
.Replay(1)
|
.Replay(1)
|
||||||
.RefCount(TimeSpan.FromMilliseconds(5000));
|
.RefCount(TimeSpan.FromMilliseconds(5000));
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.Lib;
|
using Wabbajack.Lib;
|
||||||
@ -33,7 +34,7 @@ namespace Wabbajack
|
|||||||
public ModVM TargetMod => _targetMod.Value;
|
public ModVM TargetMod => _targetMod.Value;
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> SlideShowNextItemCommand { get; } = ReactiveCommand.Create(() => { });
|
public ReactiveCommand<Unit, Unit> SlideShowNextItemCommand { get; } = ReactiveCommand.Create(() => { });
|
||||||
public ReactiveCommand<Unit, Unit> VisitNexusSiteCommand { get; }
|
public ReactiveCommand<Unit, Unit> VisitURLCommand { get; }
|
||||||
|
|
||||||
public const int PreloadAmount = 4;
|
public const int PreloadAmount = 4;
|
||||||
|
|
||||||
@ -82,23 +83,24 @@ namespace Wabbajack
|
|||||||
{
|
{
|
||||||
if (modList?.SourceModList?.Archives == null)
|
if (modList?.SourceModList?.Archives == null)
|
||||||
{
|
{
|
||||||
return Observable.Empty<NexusDownloader.State>()
|
return Observable.Empty<IMetaState>()
|
||||||
.ToObservableChangeSet(x => x.ModID);
|
.ToObservableChangeSet(x => x.URL);
|
||||||
}
|
}
|
||||||
return modList.SourceModList.Archives
|
return modList.SourceModList.Archives
|
||||||
.Select(m => m.State)
|
.Select(m => m.State)
|
||||||
.OfType<NexusDownloader.State>()
|
.OfType<IMetaState>()
|
||||||
|
.DistinctBy(x => x.URL)
|
||||||
// Shuffle it
|
// Shuffle it
|
||||||
.Shuffle(_random)
|
.Shuffle(_random)
|
||||||
.AsObservableChangeSet(x => x.ModID);
|
.AsObservableChangeSet(x => x.URL);
|
||||||
})
|
})
|
||||||
// Switch to the new list after every ModList change
|
// Switch to the new list after every ModList change
|
||||||
.Switch()
|
.Switch()
|
||||||
.Transform(nexus => new ModVM(nexus))
|
.Transform(mod => new ModVM(mod))
|
||||||
.DisposeMany()
|
.DisposeMany()
|
||||||
// Filter out any NSFW slides if we don't want them
|
// Filter out any NSFW slides if we don't want them
|
||||||
.AutoRefreshOnObservable(slide => this.WhenAny(x => x.ShowNSFW))
|
.AutoRefreshOnObservable(slide => this.WhenAny(x => x.ShowNSFW))
|
||||||
.Filter(slide => !slide.IsNSFW || ShowNSFW)
|
.Filter(slide => !slide.State.IsNSFW || ShowNSFW)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
// Find target mod to display by combining dynamic list with currently desired index
|
// Find target mod to display by combining dynamic list with currently desired index
|
||||||
@ -120,14 +122,18 @@ namespace Wabbajack
|
|||||||
.Switch()
|
.Switch()
|
||||||
.ToGuiProperty(this, nameof(Image));
|
.ToGuiProperty(this, nameof(Image));
|
||||||
|
|
||||||
VisitNexusSiteCommand = ReactiveCommand.Create(
|
VisitURLCommand = ReactiveCommand.Create(
|
||||||
execute: () =>
|
execute: () =>
|
||||||
{
|
{
|
||||||
Utils.OpenWebsite(TargetMod.ModURL);
|
Utils.OpenWebsite(TargetMod.State.URL);
|
||||||
return Unit.Default;
|
return Unit.Default;
|
||||||
},
|
},
|
||||||
canExecute: this.WhenAny(x => x.TargetMod.ModURL)
|
canExecute: this.WhenAny(x => x.TargetMod.State.URL)
|
||||||
.Select(x => x?.StartsWith("https://") ?? false)
|
.Select(x =>
|
||||||
|
{
|
||||||
|
var regex = new Regex("^(http|https):\\/\\/");
|
||||||
|
return x != null && regex.Match(x).Success;
|
||||||
|
})
|
||||||
.ObserveOnGuiThread());
|
.ObserveOnGuiThread());
|
||||||
|
|
||||||
// Preload upcoming images
|
// Preload upcoming images
|
||||||
|
@ -157,7 +157,7 @@ namespace Wabbajack
|
|||||||
};
|
};
|
||||||
await vm.Driver.WaitForInitialized();
|
await vm.Driver.WaitForInitialized();
|
||||||
IWebDriver browser = new CefSharpWrapper(vm.Browser);
|
IWebDriver browser = new CefSharpWrapper(vm.Browser);
|
||||||
vm.Instructions = $"Please Download {state.ModName} - {state.ModID} - {state.FileID}";
|
vm.Instructions = $"Please Download {state.Name} - {state.ModID} - {state.FileID}";
|
||||||
browser.DownloadHandler = uri =>
|
browser.DownloadHandler = uri =>
|
||||||
{
|
{
|
||||||
manuallyDownloadNexusFile.Resume(uri);
|
manuallyDownloadNexusFile.Resume(uri);
|
||||||
|
@ -73,7 +73,7 @@ namespace Wabbajack
|
|||||||
})
|
})
|
||||||
.BindToStrict(this, x => x.PlayPauseButton.ToolTip)
|
.BindToStrict(this, x => x.PlayPauseButton.ToolTip)
|
||||||
.DisposeWith(dispose);
|
.DisposeWith(dispose);
|
||||||
this.WhenAny(x => x.ViewModel.Slideshow.VisitNexusSiteCommand)
|
this.WhenAny(x => x.ViewModel.Slideshow.VisitURLCommand)
|
||||||
.BindToStrict(this, x => x.OpenWebsite.Command)
|
.BindToStrict(this, x => x.OpenWebsite.Command)
|
||||||
.DisposeWith(dispose);
|
.DisposeWith(dispose);
|
||||||
this.BindStrict(this.ViewModel, x => x.Slideshow.ShowNSFW, x => x.ShowNSFWButton.IsChecked,
|
this.BindStrict(this.ViewModel, x => x.Slideshow.ShowNSFW, x => x.ShowNSFWButton.IsChecked,
|
||||||
|
Loading…
Reference in New Issue
Block a user