mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Implemented manual downloader support
This commit is contained in:
parent
2ea4eda9b4
commit
7b5b483303
@ -8,6 +8,8 @@ using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ReactiveUI;
|
||||
using Wabbajack.DTOs;
|
||||
using Wabbajack.DTOs.Interventions;
|
||||
using Wabbajack.Interventions;
|
||||
using Wabbajack.LoginManagers;
|
||||
using Wabbajack.Models;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
@ -46,6 +48,7 @@ namespace Wabbajack
|
||||
services.AddOSIntegrated();
|
||||
|
||||
services.AddSingleton<CefService>();
|
||||
services.AddSingleton<IUserInterventionHandler, InteventionHandler>();
|
||||
|
||||
services.AddTransient<MainWindow>();
|
||||
services.AddTransient<MainWindowVM>();
|
||||
@ -73,6 +76,7 @@ namespace Wabbajack
|
||||
services.AddAllSingleton<INeedsLogin, LoversLabLoginManager>();
|
||||
services.AddAllSingleton<INeedsLogin, NexusLoginManager>();
|
||||
services.AddAllSingleton<INeedsLogin, VectorPlexusLoginManager>();
|
||||
services.AddSingleton<ManualDownloadHandler>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
21
Wabbajack.App.Wpf/Interventions/InteventionHandler.cs
Normal file
21
Wabbajack.App.Wpf/Interventions/InteventionHandler.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ReactiveUI;
|
||||
using Wabbajack.DTOs.Interventions;
|
||||
|
||||
namespace Wabbajack.Interventions;
|
||||
|
||||
public class InteventionHandler : IUserInterventionHandler
|
||||
{
|
||||
private readonly ILogger<InteventionHandler> _logger;
|
||||
|
||||
public InteventionHandler(ILogger<InteventionHandler> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
public void Raise(IUserIntervention intervention)
|
||||
{
|
||||
// Recast these or they won't be properly handled by the message bus
|
||||
if (intervention is ManualDownload md)
|
||||
MessageBus.Current.SendMessage(md);
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
@ -15,6 +16,7 @@ using Wabbajack.DTOs.Interventions;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Messages;
|
||||
using Wabbajack.Networking.Http.Interfaces;
|
||||
using Wabbajack.UserIntervention;
|
||||
|
||||
namespace Wabbajack.LoginManagers;
|
||||
|
||||
@ -23,6 +25,7 @@ public class LoversLabLoginManager : ViewModel, INeedsLogin
|
||||
private readonly ILogger<LoversLabLoginManager> _logger;
|
||||
private readonly ITokenProvider<LoversLabLoginState> _token;
|
||||
private readonly IUserInterventionHandler _handler;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public string SiteName { get; } = "Lovers Lab";
|
||||
public ICommand TriggerLogin { get; set; }
|
||||
@ -33,10 +36,11 @@ public class LoversLabLoginManager : ViewModel, INeedsLogin
|
||||
[Reactive]
|
||||
public bool HaveLogin { get; set; }
|
||||
|
||||
public LoversLabLoginManager(ILogger<LoversLabLoginManager> logger, ITokenProvider<LoversLabLoginState> token)
|
||||
public LoversLabLoginManager(ILogger<LoversLabLoginManager> logger, ITokenProvider<LoversLabLoginState> token, IServiceProvider serviceProvider)
|
||||
{
|
||||
_logger = logger;
|
||||
_token = token;
|
||||
_serviceProvider = serviceProvider;
|
||||
RefreshTokenState();
|
||||
|
||||
ClearLogin = ReactiveCommand.CreateFromTask(async () =>
|
||||
@ -52,8 +56,8 @@ public class LoversLabLoginManager : ViewModel, INeedsLogin
|
||||
TriggerLogin = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
_logger.LogInformation("Logging into {SiteName}", SiteName);
|
||||
await LoversLabLogin.Send();
|
||||
RefreshTokenState();
|
||||
|
||||
MessageBus.Current.SendMessage(new OpenBrowserTab(_serviceProvider.GetRequiredService<LoversLabLoginHandler>()));
|
||||
}, this.WhenAnyValue(v => v.HaveLogin).Select(v => !v));
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
@ -15,6 +16,7 @@ using Wabbajack.DTOs.Interventions;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Messages;
|
||||
using Wabbajack.Networking.Http.Interfaces;
|
||||
using Wabbajack.UserIntervention;
|
||||
|
||||
namespace Wabbajack.LoginManagers;
|
||||
|
||||
@ -23,6 +25,7 @@ public class VectorPlexusLoginManager : ViewModel, INeedsLogin
|
||||
private readonly ILogger<VectorPlexusLoginManager> _logger;
|
||||
private readonly ITokenProvider<VectorPlexusLoginState> _token;
|
||||
private readonly IUserInterventionHandler _handler;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public string SiteName { get; } = "Vector Plexus";
|
||||
public ICommand TriggerLogin { get; set; }
|
||||
@ -33,10 +36,11 @@ public class VectorPlexusLoginManager : ViewModel, INeedsLogin
|
||||
[Reactive]
|
||||
public bool HaveLogin { get; set; }
|
||||
|
||||
public VectorPlexusLoginManager(ILogger<VectorPlexusLoginManager> logger, ITokenProvider<VectorPlexusLoginState> token)
|
||||
public VectorPlexusLoginManager(ILogger<VectorPlexusLoginManager> logger, ITokenProvider<VectorPlexusLoginState> token, IServiceProvider serviceProvider)
|
||||
{
|
||||
_logger = logger;
|
||||
_token = token;
|
||||
_serviceProvider = serviceProvider;
|
||||
RefreshTokenState();
|
||||
|
||||
ClearLogin = ReactiveCommand.CreateFromTask(async () =>
|
||||
@ -52,8 +56,7 @@ public class VectorPlexusLoginManager : ViewModel, INeedsLogin
|
||||
TriggerLogin = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
_logger.LogInformation("Logging into {SiteName}", SiteName);
|
||||
await VectorPlexusLogin.Send();
|
||||
RefreshTokenState();
|
||||
MessageBus.Current.SendMessage(new OpenBrowserTab(_serviceProvider.GetRequiredService<VectorPlexusLoginHandler>()));
|
||||
}, this.WhenAnyValue(v => v.HaveLogin).Select(v => !v));
|
||||
}
|
||||
|
||||
|
27
Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs
Normal file
27
Wabbajack.App.Wpf/UserIntervention/ManualDownloadHandler.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System.Security.Policy;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Wabbajack.DTOs;
|
||||
using Wabbajack.DTOs.DownloadStates;
|
||||
using Wabbajack.DTOs.Interventions;
|
||||
using Wabbajack.Paths;
|
||||
|
||||
namespace Wabbajack.UserIntervention;
|
||||
|
||||
public class ManualDownloadHandler : BrowserTabViewModel
|
||||
{
|
||||
public ManualDownload Intervention { get; set; }
|
||||
protected override async Task Run(CancellationToken token)
|
||||
{
|
||||
await WaitForReady();
|
||||
var archive = Intervention.Archive;
|
||||
var md = Intervention.Archive.State as Manual;
|
||||
|
||||
Instructions = string.IsNullOrWhiteSpace(md.Prompt) ? $"Please download {archive.Name}" : md.Prompt;
|
||||
await NavigateTo(md.Url);
|
||||
|
||||
var uri = await WaitForDownloadUri(token);
|
||||
|
||||
Intervention.Finish(uri);
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ using Wabbajack.Services.OSIntegrated;
|
||||
|
||||
namespace Wabbajack.UserIntervention;
|
||||
|
||||
public abstract class OAuth2LoginHandler<TIntervention, TLoginType> : WebUserInterventionBase<TIntervention>
|
||||
public abstract class OAuth2LoginHandler<TIntervention, TLoginType> : BrowserTabViewModel
|
||||
where TIntervention : IUserIntervention
|
||||
where TLoginType : OAuth2LoginState, new()
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
@ -9,6 +10,7 @@ using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.Wpf;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Wabbajack.DTOs.Interventions;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Messages;
|
||||
using Wabbajack.Views;
|
||||
@ -83,11 +85,38 @@ public abstract class BrowserTabViewModel : ViewModel
|
||||
|
||||
public async Task<HtmlDocument> GetDom(CancellationToken token)
|
||||
{
|
||||
var v = HttpUtility.UrlDecode("\u003D");
|
||||
var source = await EvaluateJavaScript("document.body.outerHTML");
|
||||
var decoded = JsonSerializer.Deserialize<string>(source);
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(decoded);
|
||||
return doc;
|
||||
}
|
||||
|
||||
public async Task<ManualDownload.BrowserDownloadState> WaitForDownloadUri(CancellationToken token)
|
||||
{
|
||||
var source = new TaskCompletionSource<Uri>();
|
||||
var referer = _browser.Source;
|
||||
_browser.CoreWebView2.DownloadStarting += (sender, args) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
source.SetResult(new Uri(args.DownloadOperation.Uri));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
source.SetCanceled();
|
||||
}
|
||||
|
||||
args.Handled = true;
|
||||
args.Cancel = true;
|
||||
};
|
||||
|
||||
var uri = await source.Task.WaitAsync(token);
|
||||
var cookies = await GetCookies(uri.Host, token);
|
||||
return new ManualDownload.BrowserDownloadState(uri, cookies, new[]
|
||||
{
|
||||
("Referer", referer.ToString())
|
||||
});
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Downloaders.GameFile;
|
||||
using Wabbajack;
|
||||
using Wabbajack.DTOs.Interventions;
|
||||
using Wabbajack.Interventions;
|
||||
using Wabbajack.LoginManagers;
|
||||
using Wabbajack.Messages;
|
||||
@ -112,6 +113,10 @@ namespace Wabbajack
|
||||
MessageBus.Current.Listen<VectorPlexusLogin>()
|
||||
.Subscribe(HandleLogin)
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
MessageBus.Current.Listen<ManualDownload>()
|
||||
.Subscribe(HandleManualDownload)
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
_resourceMonitor.Updates
|
||||
.Select(r => string.Join(", ", r.Where(r => r.Throughput > 0)
|
||||
@ -178,7 +183,6 @@ namespace Wabbajack
|
||||
{
|
||||
var handler = _serviceProvider.GetRequiredService<VectorPlexusLoginHandler>();
|
||||
handler.RunWrapper(CancellationToken.None).FireAndForget();
|
||||
|
||||
}
|
||||
|
||||
private void HandleNavigateBack(NavigateBack navigateBack)
|
||||
@ -186,6 +190,13 @@ namespace Wabbajack
|
||||
ActivePane = PreviousPanes.Last();
|
||||
PreviousPanes.RemoveAt(PreviousPanes.Count - 1);
|
||||
}
|
||||
|
||||
private void HandleManualDownload(ManualDownload manualDownload)
|
||||
{
|
||||
var handler = _serviceProvider.GetRequiredService<ManualDownloadHandler>();
|
||||
handler.Intervention = manualDownload;
|
||||
MessageBus.Current.SendMessage(new OpenBrowserTab(handler));
|
||||
}
|
||||
|
||||
private void HandleNavigateTo(NavigateToGlobal.ScreenType s)
|
||||
{
|
||||
|
24
Wabbajack.DTOs/Interventions/ManualDownload.cs
Normal file
24
Wabbajack.DTOs/Interventions/ManualDownload.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Wabbajack.DTOs.Logins;
|
||||
using Wabbajack.Hashing.xxHash64;
|
||||
using Wabbajack.Paths;
|
||||
|
||||
namespace Wabbajack.DTOs.Interventions;
|
||||
|
||||
public class ManualDownload : AUserIntervention<ManualDownload.BrowserDownloadState>
|
||||
{
|
||||
public Archive Archive { get; }
|
||||
public AbsolutePath OutputPath { get; }
|
||||
|
||||
public ManualDownload(Archive archive, AbsolutePath outputPath)
|
||||
{
|
||||
Archive = archive;
|
||||
OutputPath = outputPath;
|
||||
}
|
||||
|
||||
public record BrowserDownloadState(Uri Uri, Cookie[] Cookies, (string Key, string Value)[] Headers)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -1,19 +1,57 @@
|
||||
using Wabbajack.Downloaders.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Wabbajack.Downloaders.Interfaces;
|
||||
using Wabbajack.DTOs;
|
||||
using Wabbajack.DTOs.DownloadStates;
|
||||
using Wabbajack.DTOs.Interventions;
|
||||
using Wabbajack.DTOs.Validation;
|
||||
using Wabbajack.Hashing.xxHash64;
|
||||
using Wabbajack.Paths;
|
||||
using Wabbajack.Paths.IO;
|
||||
using Wabbajack.RateLimiter;
|
||||
|
||||
namespace Wabbajack.Downloaders.Manual;
|
||||
|
||||
public class ManualDownloader : ADownloader<DTOs.DownloadStates.Manual>
|
||||
{
|
||||
public override Task<Hash> Download(Archive archive, DTOs.DownloadStates.Manual state, AbsolutePath destination, IJob job, CancellationToken token)
|
||||
private readonly ILogger<ManualDownloader> _logger;
|
||||
private readonly IUserInterventionHandler _interventionHandler;
|
||||
private readonly IResource<HttpClient> _limiter;
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public ManualDownloader(ILogger<ManualDownloader> logger, IUserInterventionHandler interventionHandler, HttpClient client)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
_logger = logger;
|
||||
_interventionHandler = interventionHandler;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public override async Task<Hash> Download(Archive archive, DTOs.DownloadStates.Manual state, AbsolutePath destination, IJob job, CancellationToken token)
|
||||
{
|
||||
_logger.LogInformation("Starting manual download of {Url}", state.Url);
|
||||
var intervention = new ManualDownload(archive, destination);
|
||||
_interventionHandler.Raise(intervention);
|
||||
var browserState = await intervention.Task;
|
||||
|
||||
var msg = new HttpRequestMessage(HttpMethod.Get, browserState.Uri);
|
||||
msg.Headers.Add("User-Agent",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36");
|
||||
msg.Headers.Add("Cookie", string.Join(";", browserState.Cookies.Select(c => $"{c.Name}={c.Value}")));
|
||||
|
||||
|
||||
foreach (var header in browserState.Headers)
|
||||
{
|
||||
msg.Headers.Add(header.Key, header.Value);
|
||||
}
|
||||
|
||||
using var response = await _client.SendAsync(msg, token);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
throw new HttpRequestException(response.ReasonPhrase, null, statusCode:response.StatusCode);
|
||||
|
||||
await using var strm = await response.Content.ReadAsStreamAsync(token);
|
||||
await using var os = destination.Open(FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
return await strm.HashingCopy(os, token, job);
|
||||
}
|
||||
|
||||
|
||||
public override async Task<bool> Prepare()
|
||||
{
|
||||
|
@ -10,4 +10,8 @@
|
||||
<ProjectReference Include="..\Wabbajack.Downloaders.Interfaces\Wabbajack.Downloaders.Interfaces.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2-mauipre.1.22054.8" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
Loading…
Reference in New Issue
Block a user