From a84394ad6ba911a50b126939e3c924e8c867810d Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Mon, 31 Jan 2022 23:07:23 -0700 Subject: [PATCH] better downgrader support, support manual Mega downloads --- .../CompilationSteps/PatchStockGameFiles.cs | 41 +++++++++++++++ Wabbajack.Lib/Downloaders/ManualDownloader.cs | 17 +++++-- Wabbajack.Lib/MO2Compiler.cs | 1 + .../ManuallyDownloadMegaFile.cs | 43 ++++++++++++++++ .../WebAutomation/CefSharpWrapper.cs | 11 ++++ .../View Models/UserInterventionHandlers.cs | 50 +++++++++++++++++++ 6 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 Wabbajack.Lib/CompilationSteps/PatchStockGameFiles.cs create mode 100644 Wabbajack.Lib/StatusMessages/ManuallyDownloadMegaFile.cs diff --git a/Wabbajack.Lib/CompilationSteps/PatchStockGameFiles.cs b/Wabbajack.Lib/CompilationSteps/PatchStockGameFiles.cs new file mode 100644 index 00000000..dfaf6e94 --- /dev/null +++ b/Wabbajack.Lib/CompilationSteps/PatchStockGameFiles.cs @@ -0,0 +1,41 @@ +using System.Linq; +using System.Threading.Tasks; +using F23.StringSimilarity; +using Wabbajack.Common; +using Wabbajack.Lib.Downloaders; + +namespace Wabbajack.Lib.CompilationSteps +{ + public class PatchStockGameFiles : ACompilationStep + { + private readonly Task> _files; + private readonly Levenshtein _distFn; + + public PatchStockGameFiles(ACompiler compiler) : base(compiler) + { + _distFn = new Levenshtein(); + _files = Task.Run(async () => (await ClientAPI.GetGameFilesFromGithub(Game.SkyrimSpecialEdition, "1.5.97.0")) + .ToLookup(f => f.Hash)); + } + + public override async ValueTask Run(RawSourceFile source) + { + if (_compiler.CompilingGame.Game != Game.SkyrimSpecialEdition) return null; + + var found = (await _files)[source.Hash]; + if (!found.Any()) return null; + + var srcFile = _compiler.IndexedArchives + .Where(f => f.State is GameFileSourceDownloader.State) + .OrderBy(l => _distFn.Distance(l.File.Name.FileName.ToString(), source.Path.FileName.ToString())) + .FirstOrDefault(); + + if (srcFile == null) return null; + + var resolved = source.EvolveTo(); + resolved.Choices = new[] {srcFile.File}; + resolved.FromHash = srcFile.File.Hash; + return resolved; + } + } +} diff --git a/Wabbajack.Lib/Downloaders/ManualDownloader.cs b/Wabbajack.Lib/Downloaders/ManualDownloader.cs index 00761849..34113416 100644 --- a/Wabbajack.Lib/Downloaders/ManualDownloader.cs +++ b/Wabbajack.Lib/Downloaders/ManualDownloader.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; using System.Reactive.Subjects; using System.Threading; @@ -54,9 +55,17 @@ namespace Wabbajack.Lib.Downloaders public override async Task Download(Archive a, AbsolutePath destination) { - var (uri, client) = await Utils.Log(await ManuallyDownloadFile.Create(this)).Task; - var state = new HTTPDownloader.State(uri.ToString()) { Client = client }; - return await state.Download(a, destination); + if ((new Uri(Url)).Host == "mega.nz") + { + await Utils.Log(await ManuallyDownloadMegaFile.Create(this, destination)).Task; + return true; + } + else + { + var (uri, client) = await Utils.Log(await ManuallyDownloadFile.Create(this)).Task; + var state = new HTTPDownloader.State(uri.ToString()) {Client = client}; + return await state.Download(a, destination); + } } public override async Task Verify(Archive a, CancellationToken? token) diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index da6702df..8b7c048e 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -460,6 +460,7 @@ namespace Wabbajack.Lib new IncludeRegex(this, "^[^\\\\]*\\.bat$"), new IncludeModIniData(this), new DirectMatch(this), + new PatchStockGameFiles(this), new IncludeTaggedMods(this, Consts.WABBAJACK_INCLUDE), new IncludeTaggedFolders(this, Consts.WABBAJACK_INCLUDE), new IgnoreEndsWith(this, ".pyc"), diff --git a/Wabbajack.Lib/StatusMessages/ManuallyDownloadMegaFile.cs b/Wabbajack.Lib/StatusMessages/ManuallyDownloadMegaFile.cs new file mode 100644 index 00000000..aafabe7e --- /dev/null +++ b/Wabbajack.Lib/StatusMessages/ManuallyDownloadMegaFile.cs @@ -0,0 +1,43 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Wabbajack.Common; +using Wabbajack.Lib.Downloaders; + +namespace Wabbajack.Lib +{ + public class ManuallyDownloadMegaFile : AUserIntervention + { + public ManualDownloader.State State { get; } + public override string ShortDescription { get; } = string.Empty; + public override string ExtendedDescription { get; } = string.Empty; + + private TaskCompletionSource _tcs = new(); + public Task Task => _tcs.Task; + + + public AbsolutePath Destination { get; } + + private ManuallyDownloadMegaFile(ManualDownloader.State state, AbsolutePath destination) + { + State = state; + Destination = destination; + } + + + public static async Task Create(ManualDownloader.State state, AbsolutePath destination) + { + var result = new ManuallyDownloadMegaFile(state, destination); + return result; + } + public override void Cancel() + { + _tcs.SetCanceled(); + } + + public void Resume() + { + _tcs.SetResult(); + } + } +} diff --git a/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs b/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs index 1782e14f..7cf7b6ba 100644 --- a/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs +++ b/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Reactive.Disposables; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -26,6 +27,16 @@ namespace Wabbajack.Lib.WebAutomation _browser.LifeSpanHandler = new PopupBlocker(this); } + public IDisposable SetDownloadHandler(IDownloadHandler handler) + { + var oldVal = _browser.DownloadHandler; + _browser.DownloadHandler = handler; + return Disposable.Create(oldVal, ov => + { + _browser.DownloadHandler = ov; + }); + } + public Task NavigateTo(Uri uri, CancellationToken? token = null) { var tcs = new TaskCompletionSource(); diff --git a/Wabbajack/View Models/UserInterventionHandlers.cs b/Wabbajack/View Models/UserInterventionHandlers.cs index 5d31924e..6e80ed81 100644 --- a/Wabbajack/View Models/UserInterventionHandlers.cs +++ b/Wabbajack/View Models/UserInterventionHandlers.cs @@ -84,6 +84,9 @@ namespace Wabbajack case ManuallyDownloadFile c: await WrapBrowserJob(c, (vm, cancel) => HandleManualDownload(vm, cancel, c)); break; + case ManuallyDownloadMegaFile c: + await WrapBrowserJob(c, (vm, cancel) => HandleManualMegaDownload(vm, cancel, c)); + break; case AbstractNeedsLoginDownloader.RequestSiteLogin c: await WrapBrowserJob(c, async (vm, cancel) => { @@ -187,6 +190,53 @@ namespace Wabbajack } } + + private async Task HandleManualMegaDownload(WebBrowserVM vm, CancellationTokenSource cancel, ManuallyDownloadMegaFile manuallyDownloadFile) + { + var browser = new CefSharpWrapper(vm.Browser); + vm.Instructions = $"Please locate and download {manuallyDownloadFile.State.Url}"; + + await vm.Driver.WaitForInitialized(); + var tcs = new TaskCompletionSource(); + + using var _ = browser.SetDownloadHandler(new BlobDownloadHandler(manuallyDownloadFile, tcs)); + + await browser.NavigateTo(new Uri(manuallyDownloadFile.State.Url)); + + while (!cancel.IsCancellationRequested && !tcs.Task.IsCompleted) + { + await Task.Delay(100); + } + manuallyDownloadFile.Resume(); + + } + + private class BlobDownloadHandler : IDownloadHandler + { + private readonly ManuallyDownloadMegaFile _manualFile; + private readonly TaskCompletionSource _tcs; + + public BlobDownloadHandler(ManuallyDownloadMegaFile f, TaskCompletionSource tcs) + { + _manualFile = f; + _tcs = tcs; + } + public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, + IBeforeDownloadCallback callback) + { + callback.Continue(_manualFile.ToString(), false); + } + + public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, + IDownloadItemCallback callback) + { + if (downloadItem.IsComplete) + { + _tcs.TrySetResult(); + } + callback.Resume(); + } + } private async Task HandleManualNexusDownload(WebBrowserVM vm, CancellationTokenSource cancel, ManuallyDownloadNexusFile manuallyDownloadNexusFile) {