diff --git a/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs b/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs
new file mode 100644
index 00000000..61a83a81
--- /dev/null
+++ b/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs
@@ -0,0 +1,142 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Reactive.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using ReactiveUI;
+using Wabbajack.Common;
+using Wabbajack.Common.StatusFeed;
+using Wabbajack.Lib.LibCefHelpers;
+using Wabbajack.Lib.WebAutomation;
+
+namespace Wabbajack.Lib.Downloaders
+{
+ public abstract class AbstractNeedsLoginDownloader : INeedsLogin
+ {
+ private readonly Uri _loginUri;
+ private readonly string _encryptedKeyName;
+ private readonly string _cookieDomain;
+ private readonly string _cookieName;
+ protected HttpClient AuthedClient;
+
+ ///
+ /// Sets up all the login facilites needed for a INeedsLogin downloader based on having the user log
+ /// in via a browser
+ ///
+ /// The URI to preset for logging in
+ /// The name of the encrypted JSON key in which to store cookies
+ /// The cookie domain to scan
+ /// The cookie name to wait for
+ public AbstractNeedsLoginDownloader(Uri loginUri,
+ string encryptedKeyName,
+ string cookieDomain,
+ string cookieName)
+ {
+ _loginUri = loginUri;
+ _encryptedKeyName = encryptedKeyName;
+ _cookieDomain = cookieDomain;
+ _cookieName = cookieName;
+
+ TriggerLogin = ReactiveCommand.CreateFromTask(
+ execute: () => Utils.CatchAndLog(async () => await Utils.Log(new RequestSiteLogin(this)).Task),
+ canExecute: IsLoggedIn.Select(b => !b).ObserveOn(RxApp.MainThreadScheduler));
+ ClearLogin = ReactiveCommand.Create(
+ execute: () => Utils.CatchAndLog(() => Utils.DeleteEncryptedJson(_encryptedKeyName)),
+ canExecute: IsLoggedIn.ObserveOn(RxApp.MainThreadScheduler));
+ }
+
+ public ICommand TriggerLogin { get; }
+ public ICommand ClearLogin { get; }
+ public IObservable IsLoggedIn => Utils.HaveEncryptedJsonObservable(_encryptedKeyName);
+ public abstract string SiteName { get; }
+ public virtual string MetaInfo { get; }
+ public abstract Uri SiteURL { get; }
+ public virtual Uri IconUri { get; }
+
+ protected virtual async Task WhileWaiting(IWebDriver browser)
+ {
+ }
+
+ public async Task GetAndCacheCookies(IWebDriver browser, Action updateStatus, CancellationToken cancel)
+ {
+ updateStatus($"Please Log Into {SiteName}");
+ await browser.NavigateTo(_loginUri);
+ var cookies = new Helpers.Cookie[0];
+ while (true)
+ {
+ cancel.ThrowIfCancellationRequested();
+ await WhileWaiting(browser);
+ cookies = (await browser.GetCookies(_cookieDomain));
+ if (cookies.FirstOrDefault(c => c.Name == _cookieName) != null)
+ break;
+ await Task.Delay(500, cancel);
+ }
+
+ cookies.ToEcryptedJson(_encryptedKeyName);
+
+ return cookies;
+ }
+
+ public async Task GetAuthedClient()
+ {
+ Helpers.Cookie[] cookies;
+ try
+ {
+ cookies = Utils.FromEncryptedJson(_encryptedKeyName);
+ if (cookies != null)
+ return Helpers.GetClient(cookies, SiteURL.ToString());
+ }
+ catch (FileNotFoundException) { }
+
+ cookies = await Utils.Log(new RequestSiteLogin(this)).Task;
+ return Helpers.GetClient(cookies, SiteURL.ToString());
+ }
+
+ public async Task Prepare()
+ {
+ AuthedClient = (await GetAuthedClient()) ?? throw new NotLoggedInError(this);
+ }
+
+ public class NotLoggedInError : Exception
+ {
+ public AbstractNeedsLoginDownloader Downloader { get; }
+ public NotLoggedInError(AbstractNeedsLoginDownloader downloader) : base(
+ $"Not logged into {downloader.SiteName}, can't continue")
+ {
+ Downloader = downloader;
+ }
+ }
+
+
+ public class RequestSiteLogin : AUserIntervention
+ {
+ public AbstractNeedsLoginDownloader Downloader { get; }
+ public RequestSiteLogin(AbstractNeedsLoginDownloader downloader)
+ {
+ Downloader = downloader;
+ }
+ public override string ShortDescription => $"Getting {Downloader.SiteName} Login";
+ public override string ExtendedDescription { get; }
+
+ private readonly TaskCompletionSource _source = new TaskCompletionSource();
+ public Task Task => _source.Task;
+
+ public void Resume(Helpers.Cookie[] cookies)
+ {
+ Handled = true;
+ _source.SetResult(cookies);
+ }
+
+ public override void Cancel()
+ {
+ Handled = true;
+ _source.TrySetCanceled();
+ }
+ }
+ }
+
+
+}
diff --git a/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs b/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs
index 1802b605..87d4edf4 100644
--- a/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs
+++ b/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs
@@ -10,6 +10,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Windows.Input;
+using CefSharp;
using ReactiveUI;
using Wabbajack.Common;
using Wabbajack.Lib.LibCefHelpers;
@@ -20,32 +21,17 @@ using File = Alphaleonis.Win32.Filesystem.File;
namespace Wabbajack.Lib.Downloaders
{
- public class LoversLabDownloader : IDownloader, INeedsLogin
+ public class LoversLabDownloader : AbstractNeedsLoginDownloader, IDownloader
{
- internal HttpClient _authedClient;
-
-
#region INeedsDownload
-
- public ICommand TriggerLogin { get; }
- public ICommand ClearLogin { get; }
- public IObservable IsLoggedIn => Utils.HaveEncryptedJsonObservable("loverslabcookies");
- public string SiteName => "Lovers Lab";
- public string MetaInfo => "";
- public Uri SiteURL => new Uri("https://loverslab.com");
- public Uri IconUri => new Uri("https://www.loverslab.com/favicon.ico");
-
-
+ public override string SiteName => "Lovers Lab";
+ public override Uri SiteURL => new Uri("https://loverslab.com");
+ public override Uri IconUri => new Uri("https://www.loverslab.com/favicon.ico");
#endregion
- public LoversLabDownloader()
+ public LoversLabDownloader() : base(new Uri("https://www.loverslab.com/login"),
+ "loverslabcookies", "loverslab.com", "ips4_member_id")
{
- TriggerLogin = ReactiveCommand.CreateFromTask(
- execute: () => Utils.CatchAndLog(async () => await Utils.Log(new RequestLoversLabLogin()).Task),
- canExecute: IsLoggedIn.Select(b => !b).ObserveOn(RxApp.MainThreadScheduler));
- ClearLogin = ReactiveCommand.Create(
- execute: () => Utils.CatchAndLog(() => Utils.DeleteEncryptedJson("loverslabcookies")),
- canExecute: IsLoggedIn.ObserveOn(RxApp.MainThreadScheduler));
}
@@ -62,58 +48,17 @@ namespace Wabbajack.Lib.Downloaders
FileName = file
};
}
-
- public async Task Prepare()
+ protected override async Task WhileWaiting(IWebDriver browser)
{
- _authedClient = (await GetAuthedClient()) ?? throw new Exception("not logged into LL, TODO");
- }
-
- public static async Task GetAndCacheLoversLabCookies(IWebDriver browser, Action updateStatus, CancellationToken cancel)
- {
- updateStatus("Please Log Into Lovers Lab");
- await browser.NavigateTo(new Uri("https://www.loverslab.com/login"));
- async Task CleanAds()
- {
- try
- {
- await browser.EvaluateJavaScript(
- "document.querySelectorAll(\".ll_adblock\").forEach(function (itm) { itm.innerHTML = \"\";});");
- }
- catch (Exception ex)
- {
- Utils.Error(ex);
- }
- return false;
- }
- var cookies = new Helpers.Cookie[0];
- while (true)
- {
- cancel.ThrowIfCancellationRequested();
- await CleanAds();
- cookies = (await browser.GetCookies("loverslab.com"));
- if (cookies.FirstOrDefault(c => c.Name == "ips4_member_id") != null)
- break;
- await Task.Delay(500, cancel);
- }
-
- cookies.ToEcryptedJson("loverslabcookies");
-
- return cookies;
- }
-
- public async Task GetAuthedClient()
- {
- Helpers.Cookie[] cookies;
try
{
- cookies = Utils.FromEncryptedJson("loverslabcookies");
- if (cookies != null)
- return Helpers.GetClient(cookies, "https://www.loverslab.com");
+ await browser.EvaluateJavaScript(
+ "document.querySelectorAll(\".ll_adblock\").forEach(function (itm) { itm.innerHTML = \"\";});");
+ }
+ catch (Exception ex)
+ {
+ Utils.Error(ex);
}
- catch (FileNotFoundException) { }
-
- cookies = await Utils.Log(new RequestLoversLabLogin()).Task;
- return Helpers.GetClient(cookies, "https://www.loverslab.com");
}
public class State : AbstractDownloadState
@@ -141,7 +86,7 @@ namespace Wabbajack.Lib.Downloaders
{
var result = DownloadDispatcher.GetInstance();
TOP:
- var html = await result._authedClient.GetStringAsync(
+ var html = await result.AuthedClient.GetStringAsync(
$"https://www.loverslab.com/files/file/{FileName}/?do=download&r={FileID}");
var pattern = new Regex("(?<=csrfKey=).*(?=[&\"\'])");
@@ -153,7 +98,7 @@ namespace Wabbajack.Lib.Downloaders
var url =
$"https://www.loverslab.com/files/file/{FileName}/?do=download&r={FileID}&confirm=1&t=1&csrfKey={csrfKey}";
- var streamResult = await result._authedClient.GetAsync(url);
+ var streamResult = await result.AuthedClient.GetAsync(url);
if (streamResult.StatusCode != HttpStatusCode.OK)
{
Utils.Error(new InvalidOperationException(), $"LoversLab servers reported an error for file: {FileID}");
@@ -208,25 +153,4 @@ namespace Wabbajack.Lib.Downloaders
}
}
-
- public class RequestLoversLabLogin : AUserIntervention
- {
- public override string ShortDescription => "Getting LoversLab information";
- public override string ExtendedDescription { get; }
-
- private readonly TaskCompletionSource _source = new TaskCompletionSource();
- public Task Task => _source.Task;
-
- public void Resume(Helpers.Cookie[] cookies)
- {
- Handled = true;
- _source.SetResult(cookies);
- }
-
- public override void Cancel()
- {
- Handled = true;
- _source.TrySetCanceled();
- }
- }
}
diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj
index a78d73b3..93863e14 100644
--- a/Wabbajack.Lib/Wabbajack.Lib.csproj
+++ b/Wabbajack.Lib/Wabbajack.Lib.csproj
@@ -123,6 +123,7 @@
+
diff --git a/Wabbajack/View Models/UserInterventionHandlers.cs b/Wabbajack/View Models/UserInterventionHandlers.cs
index 3694bbb8..5305cb96 100644
--- a/Wabbajack/View Models/UserInterventionHandlers.cs
+++ b/Wabbajack/View Models/UserInterventionHandlers.cs
@@ -65,11 +65,11 @@ namespace Wabbajack
c.Resume(key);
});
break;
- case RequestLoversLabLogin c:
+ case AbstractNeedsLoginDownloader.RequestSiteLogin c:
await WrapBrowserJob(msg, async (vm, cancel) =>
{
await vm.Driver.WaitForInitialized();
- var data = await LoversLabDownloader.GetAndCacheLoversLabCookies(new CefSharpWrapper(vm.Browser), m => vm.Instructions = m, cancel.Token);
+ var data = await c.Downloader.GetAndCacheCookies(new CefSharpWrapper(vm.Browser), m => vm.Instructions = m, cancel.Token);
c.Resume(data);
});
break;