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
|
||||
|
||||
#### 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
|
||||
* 1.0, first non-beta release
|
||||
|
||||
|
@ -223,7 +223,7 @@ namespace Wabbajack.Common
|
||||
|
||||
return sha.Hash.ToBase64();
|
||||
}
|
||||
|
||||
|
||||
public static string StringSHA256Hex(this string s)
|
||||
{
|
||||
var sha = new SHA256Managed();
|
||||
|
@ -78,6 +78,27 @@ namespace Wabbajack.Lib
|
||||
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()
|
||||
{
|
||||
Utils.Log($"Exporting ModList to {ModListOutputFile}");
|
||||
|
@ -30,7 +30,7 @@ namespace Wabbajack.Lib
|
||||
typeof(PropertyFile), typeof(SteamMeta), typeof(SteamWorkshopDownloader), typeof(SteamWorkshopDownloader.State),
|
||||
typeof(LoversLabDownloader.State), typeof(GameFileSourceDownloader.State), typeof(VectorPlexusDownloader.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;
|
||||
|
@ -7,10 +7,23 @@ using Wabbajack.Lib.Validation;
|
||||
|
||||
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 static List<Type> KnownSubTypes = new List<Type>()
|
||||
public static List<Type> KnownSubTypes = new List<Type>
|
||||
{
|
||||
typeof(HTTPDownloader.State),
|
||||
typeof(GameFileSourceDownloader.State),
|
||||
|
@ -5,6 +5,7 @@ using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using HtmlAgilityPack;
|
||||
using Newtonsoft.Json;
|
||||
using Wabbajack.Common;
|
||||
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
|
||||
// same, so we can fairly easily abstract the state.
|
||||
// Pass in the state type via TState
|
||||
public abstract class AbstractIPS4Downloader<TDownloader, TState> : AbstractNeedsLoginDownloader, IDownloader
|
||||
where TState : AbstractIPS4Downloader<TDownloader, TState>.State<TDownloader>, new()
|
||||
public abstract class AbstractIPS4Downloader<TDownloader, TState> : AbstractNeedsLoginDownloader, IDownloader
|
||||
where TState : AbstractIPS4Downloader<TDownloader, TState>.State<TDownloader>, new()
|
||||
where TDownloader : IDownloader
|
||||
{
|
||||
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 FileName { get; set; }
|
||||
@ -69,10 +70,12 @@ namespace Wabbajack.Lib.Downloaders
|
||||
private static bool IsHTTPS => Downloader.SiteURL.AbsolutePath.StartsWith("https://");
|
||||
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}"
|
||||
: Downloader.SiteURL.ToString();
|
||||
|
||||
public static AbstractNeedsLoginDownloader Downloader => (AbstractNeedsLoginDownloader)(object)DownloadDispatcher.GetInstance<TDownloader>();
|
||||
|
||||
public override object[] PrimaryKey
|
||||
{
|
||||
get
|
||||
@ -100,13 +103,13 @@ namespace Wabbajack.Lib.Downloaders
|
||||
|
||||
private async Task<Stream> ResolveDownloadStream()
|
||||
{
|
||||
var downloader = (AbstractNeedsLoginDownloader)(object)DownloadDispatcher.GetInstance<TDownloader>();
|
||||
//var downloader = (AbstractNeedsLoginDownloader)(object)DownloadDispatcher.GetInstance<TDownloader>();
|
||||
|
||||
TOP:
|
||||
var csrfurl = FileID == null
|
||||
? $"{Site}/files/file/{FileName}/?do=download"
|
||||
: $"{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 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}";
|
||||
|
||||
|
||||
var streamResult = await downloader.AuthedClient.GetAsync(url);
|
||||
var streamResult = await Downloader.AuthedClient.GetAsync(url);
|
||||
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;
|
||||
@ -138,7 +141,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
var secs = times.Download - times.CurrentTime;
|
||||
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);
|
||||
}
|
||||
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) :
|
||||
|
@ -1,24 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
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.Web;
|
||||
using System.Windows.Input;
|
||||
using CefSharp;
|
||||
using ReactiveUI;
|
||||
using HtmlAgilityPack;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib.LibCefHelpers;
|
||||
using Wabbajack.Lib.NexusApi;
|
||||
using Wabbajack.Lib.Validation;
|
||||
using Wabbajack.Lib.WebAutomation;
|
||||
using File = Alphaleonis.Win32.Filesystem.File;
|
||||
|
||||
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 IconUri => new Uri("https://www.loverslab.com/favicon.ico");
|
||||
#endregion
|
||||
|
||||
public LoversLabDownloader() : base(new Uri("https://www.loverslab.com/login"),
|
||||
"loverslabcookies", "loverslab.com")
|
||||
{
|
||||
@ -46,8 +30,31 @@ namespace Wabbajack.Lib.Downloaders
|
||||
Utils.Error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
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.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Ceras;
|
||||
using ReactiveUI;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Common.StatusFeed.Errors;
|
||||
using Wabbajack.Lib.NexusApi;
|
||||
using Wabbajack.Lib.Validation;
|
||||
using Game = Wabbajack.Common.Game;
|
||||
|
||||
namespace Wabbajack.Lib.Downloaders
|
||||
{
|
||||
@ -69,21 +71,18 @@ namespace Wabbajack.Lib.Downloaders
|
||||
Utils.Error($"Error getting mod info for Nexus mod with {general.modID}");
|
||||
throw;
|
||||
}
|
||||
|
||||
return new State
|
||||
{
|
||||
GameName = general.gameName,
|
||||
FileID = general.fileID,
|
||||
ModID = general.modID,
|
||||
Name = NexusApiUtils.FixupSummary(info.name),
|
||||
Author = NexusApiUtils.FixupSummary(info.author),
|
||||
Version = general.version ?? "0.0.0.0",
|
||||
Author = info.author,
|
||||
UploadedBy = info.uploaded_by,
|
||||
UploaderProfile = info.uploaded_users_profile_url,
|
||||
ModName = info.name,
|
||||
SlideShowPic = info.picture_url,
|
||||
NexusURL = NexusApiUtils.GetModURL(game, info.mod_id),
|
||||
Summary = info.summary,
|
||||
Adult = info.contains_adult_content
|
||||
|
||||
ImageURL = info.picture_url,
|
||||
IsNSFW = info.contains_adult_content,
|
||||
Description = NexusApiUtils.FixupSummary(info.summary),
|
||||
GameName = general.gameName,
|
||||
ModID = general.modID,
|
||||
FileID = general.fileID
|
||||
};
|
||||
}
|
||||
|
||||
@ -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 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 ModID { get; set; }
|
||||
public string UploadedBy { 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 string FileID { get; set; }
|
||||
|
||||
public override object[] PrimaryKey { get => new object[]{GameName, ModID, FileID};}
|
||||
|
||||
@ -192,7 +201,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ namespace Wabbajack.Lib
|
||||
protected override async Task<bool> _Begin(CancellationToken cancel)
|
||||
{
|
||||
if (cancel.IsCancellationRequested) return false;
|
||||
ConfigureProcessor(19, ConstructDynamicNumThreads(await RecommendQueueSize()));
|
||||
ConfigureProcessor(20, ConstructDynamicNumThreads(await RecommendQueueSize()));
|
||||
UpdateTracker.Reset();
|
||||
UpdateTracker.NextStep("Gathering information");
|
||||
Info("Looking for other profiles");
|
||||
@ -279,6 +279,9 @@ namespace Wabbajack.Lib
|
||||
UpdateTracker.NextStep("Building Patches");
|
||||
await BuildPatches();
|
||||
|
||||
UpdateTracker.NextStep("Gathering Metadata");
|
||||
await GatherMetaData();
|
||||
|
||||
ModList = new ModList
|
||||
{
|
||||
GameType = CompilingGame.Game,
|
||||
|
@ -284,7 +284,7 @@ namespace Wabbajack.Lib.NexusApi
|
||||
|
||||
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();
|
||||
}
|
||||
catch (TaskCanceledException ex)
|
||||
|
@ -113,7 +113,7 @@ namespace Wabbajack.Lib.Validation
|
||||
if (nexus_mod_permissions.TryGetValue(p.ArchiveHashPath[0], out var archive))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
var url = (archive.archive.State as NexusDownloader.State).NexusURL;
|
||||
var url = (archive.archive.State as NexusDownloader.State).URL;
|
||||
if (!(archive.permissions.CanExtractBSAs ?? true) &&
|
||||
p.ArchiveHashPath.Skip(1).ButLast().Any(a => Consts.SupportedBSAs.Contains(Path.GetExtension(a).ToLower())))
|
||||
{
|
||||
|
@ -274,7 +274,7 @@ namespace Wabbajack
|
||||
_titleText = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModList)
|
||||
.Select(modList => modList?.Name ?? string.Empty),
|
||||
this.WhenAny(x => x.Slideshow.TargetMod.ModName)
|
||||
this.WhenAny(x => x.Slideshow.TargetMod.State.Name)
|
||||
.StartWith(default(string)),
|
||||
this.WhenAny(x => x.Installing),
|
||||
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
||||
@ -282,7 +282,7 @@ namespace Wabbajack
|
||||
_authorText = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModList)
|
||||
.Select(modList => modList?.Author ?? string.Empty),
|
||||
this.WhenAny(x => x.Slideshow.TargetMod.ModAuthor)
|
||||
this.WhenAny(x => x.Slideshow.TargetMod.State.Author)
|
||||
.StartWith(default(string)),
|
||||
this.WhenAny(x => x.Installing),
|
||||
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
||||
@ -290,7 +290,7 @@ namespace Wabbajack
|
||||
_description = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModList)
|
||||
.Select(modList => modList?.Description ?? string.Empty),
|
||||
this.WhenAny(x => x.Slideshow.TargetMod.ModDescription)
|
||||
this.WhenAny(x => x.Slideshow.TargetMod.State.Description)
|
||||
.StartWith(default(string)),
|
||||
this.WhenAny(x => x.Installing),
|
||||
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
||||
|
@ -38,6 +38,7 @@ namespace Wabbajack
|
||||
catch (Exception ex)
|
||||
{
|
||||
Error = ex;
|
||||
Utils.Error(ex, "Exception while loading the modlist!");
|
||||
}
|
||||
|
||||
ImageObservable = Observable.Return(Unit.Default)
|
||||
|
@ -1,49 +1,29 @@
|
||||
using ReactiveUI;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Lib.Downloaders;
|
||||
using Wabbajack.Lib.NexusApi;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public class ModVM : ViewModel
|
||||
{
|
||||
public string ModName { 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; }
|
||||
public IMetaState State { get; }
|
||||
|
||||
// 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,
|
||||
// and the cached image will automatically be released when the last interested party is gone.
|
||||
public IObservable<BitmapImage> ImageObservable { get; }
|
||||
|
||||
public ModVM(NexusDownloader.State m)
|
||||
public ModVM(IMetaState state)
|
||||
{
|
||||
ModName = NexusApiUtils.FixupSummary(m.ModName);
|
||||
ModID = m.ModID;
|
||||
ModDescription = NexusApiUtils.FixupSummary(m.Summary);
|
||||
ModAuthor = NexusApiUtils.FixupSummary(m.Author);
|
||||
IsNSFW = m.Adult;
|
||||
ModURL = m.NexusURL;
|
||||
ImageURL = m.SlideShowPic;
|
||||
ImageObservable = Observable.Return(ImageURL)
|
||||
State = state;
|
||||
|
||||
ImageObservable = Observable.Return(State.ImageURL)
|
||||
.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)
|
||||
.RefCount(TimeSpan.FromMilliseconds(5000));
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
@ -33,7 +34,7 @@ namespace Wabbajack
|
||||
public ModVM TargetMod => _targetMod.Value;
|
||||
|
||||
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;
|
||||
|
||||
@ -82,23 +83,24 @@ namespace Wabbajack
|
||||
{
|
||||
if (modList?.SourceModList?.Archives == null)
|
||||
{
|
||||
return Observable.Empty<NexusDownloader.State>()
|
||||
.ToObservableChangeSet(x => x.ModID);
|
||||
return Observable.Empty<IMetaState>()
|
||||
.ToObservableChangeSet(x => x.URL);
|
||||
}
|
||||
return modList.SourceModList.Archives
|
||||
.Select(m => m.State)
|
||||
.OfType<NexusDownloader.State>()
|
||||
.OfType<IMetaState>()
|
||||
.DistinctBy(x => x.URL)
|
||||
// Shuffle it
|
||||
.Shuffle(_random)
|
||||
.AsObservableChangeSet(x => x.ModID);
|
||||
.AsObservableChangeSet(x => x.URL);
|
||||
})
|
||||
// Switch to the new list after every ModList change
|
||||
.Switch()
|
||||
.Transform(nexus => new ModVM(nexus))
|
||||
.Transform(mod => new ModVM(mod))
|
||||
.DisposeMany()
|
||||
// Filter out any NSFW slides if we don't want them
|
||||
.AutoRefreshOnObservable(slide => this.WhenAny(x => x.ShowNSFW))
|
||||
.Filter(slide => !slide.IsNSFW || ShowNSFW)
|
||||
.Filter(slide => !slide.State.IsNSFW || ShowNSFW)
|
||||
.RefCount();
|
||||
|
||||
// Find target mod to display by combining dynamic list with currently desired index
|
||||
@ -120,14 +122,18 @@ namespace Wabbajack
|
||||
.Switch()
|
||||
.ToGuiProperty(this, nameof(Image));
|
||||
|
||||
VisitNexusSiteCommand = ReactiveCommand.Create(
|
||||
VisitURLCommand = ReactiveCommand.Create(
|
||||
execute: () =>
|
||||
{
|
||||
Utils.OpenWebsite(TargetMod.ModURL);
|
||||
Utils.OpenWebsite(TargetMod.State.URL);
|
||||
return Unit.Default;
|
||||
},
|
||||
canExecute: this.WhenAny(x => x.TargetMod.ModURL)
|
||||
.Select(x => x?.StartsWith("https://") ?? false)
|
||||
canExecute: this.WhenAny(x => x.TargetMod.State.URL)
|
||||
.Select(x =>
|
||||
{
|
||||
var regex = new Regex("^(http|https):\\/\\/");
|
||||
return x != null && regex.Match(x).Success;
|
||||
})
|
||||
.ObserveOnGuiThread());
|
||||
|
||||
// Preload upcoming images
|
||||
|
@ -157,7 +157,7 @@ namespace Wabbajack
|
||||
};
|
||||
await vm.Driver.WaitForInitialized();
|
||||
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 =>
|
||||
{
|
||||
manuallyDownloadNexusFile.Resume(uri);
|
||||
|
@ -73,7 +73,7 @@ namespace Wabbajack
|
||||
})
|
||||
.BindToStrict(this, x => x.PlayPauseButton.ToolTip)
|
||||
.DisposeWith(dispose);
|
||||
this.WhenAny(x => x.ViewModel.Slideshow.VisitNexusSiteCommand)
|
||||
this.WhenAny(x => x.ViewModel.Slideshow.VisitURLCommand)
|
||||
.BindToStrict(this, x => x.OpenWebsite.Command)
|
||||
.DisposeWith(dispose);
|
||||
this.BindStrict(this.ViewModel, x => x.Slideshow.ShowNSFW, x => x.ShowNSFWButton.IsChecked,
|
||||
|
Loading…
Reference in New Issue
Block a user