mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Merge pull request #353 from wabbajack-tools/abstract-login-downloader
Reworked the LL downloader
This commit is contained in:
commit
27f0f98671
142
Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs
Normal file
142
Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs
Normal file
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Sets up all the login facilites needed for a INeedsLogin downloader based on having the user log
|
||||
/// in via a browser
|
||||
/// </summary>
|
||||
/// <param name="loginUri">The URI to preset for logging in</param>
|
||||
/// <param name="encryptedKeyName">The name of the encrypted JSON key in which to store cookies</param>
|
||||
/// <param name="cookieDomain">The cookie domain to scan</param>
|
||||
/// <param name="cookieName">The cookie name to wait for</param>
|
||||
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<bool> 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<Helpers.Cookie[]> GetAndCacheCookies(IWebDriver browser, Action<string> 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<HttpClient> GetAuthedClient()
|
||||
{
|
||||
Helpers.Cookie[] cookies;
|
||||
try
|
||||
{
|
||||
cookies = Utils.FromEncryptedJson<Helpers.Cookie[]>(_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<Helpers.Cookie[]> _source = new TaskCompletionSource<Helpers.Cookie[]>();
|
||||
public Task<Helpers.Cookie[]> Task => _source.Task;
|
||||
|
||||
public void Resume(Helpers.Cookie[] cookies)
|
||||
{
|
||||
Handled = true;
|
||||
_source.SetResult(cookies);
|
||||
}
|
||||
|
||||
public override void Cancel()
|
||||
{
|
||||
Handled = true;
|
||||
_source.TrySetCanceled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<bool> 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<Helpers.Cookie[]> GetAndCacheLoversLabCookies(IWebDriver browser, Action<string> updateStatus, CancellationToken cancel)
|
||||
{
|
||||
updateStatus("Please Log Into Lovers Lab");
|
||||
await browser.NavigateTo(new Uri("https://www.loverslab.com/login"));
|
||||
async Task<bool> 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<HttpClient> GetAuthedClient()
|
||||
{
|
||||
Helpers.Cookie[] cookies;
|
||||
try
|
||||
{
|
||||
cookies = Utils.FromEncryptedJson<Helpers.Cookie[]>("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<LoversLabDownloader>();
|
||||
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<Helpers.Cookie[]> _source = new TaskCompletionSource<Helpers.Cookie[]>();
|
||||
public Task<Helpers.Cookie[]> Task => _source.Task;
|
||||
|
||||
public void Resume(Helpers.Cookie[] cookies)
|
||||
{
|
||||
Handled = true;
|
||||
_source.SetResult(cookies);
|
||||
}
|
||||
|
||||
public override void Cancel()
|
||||
{
|
||||
Handled = true;
|
||||
_source.TrySetCanceled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,6 +123,7 @@
|
||||
<Compile Include="CompilationSteps\IStackStep.cs" />
|
||||
<Compile Include="CompilationSteps\PatchStockESMs.cs" />
|
||||
<Compile Include="CompilationSteps\Serialization.cs" />
|
||||
<Compile Include="Downloaders\AbstractNeedsLoginDownloader.cs" />
|
||||
<Compile Include="Downloaders\GameFileSourceDownloader.cs" />
|
||||
<Compile Include="Downloaders\INeedsLogin.cs" />
|
||||
<Compile Include="Downloaders\LoversLabDownloader.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;
|
||||
|
Loading…
Reference in New Issue
Block a user