2021-09-27 12:42:46 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2022-06-08 13:12:44 +00:00
|
|
|
|
using System.IO;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net.Http;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using HtmlAgilityPack;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
2022-08-21 20:23:11 +00:00
|
|
|
|
using Wabbajack.Common;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
using Wabbajack.Downloaders.Interfaces;
|
|
|
|
|
using Wabbajack.DTOs;
|
|
|
|
|
using Wabbajack.DTOs.DownloadStates;
|
|
|
|
|
using Wabbajack.DTOs.Validation;
|
|
|
|
|
using Wabbajack.Hashing.xxHash64;
|
|
|
|
|
using Wabbajack.Networking.Http.Interfaces;
|
|
|
|
|
using Wabbajack.Paths;
|
|
|
|
|
using Wabbajack.RateLimiter;
|
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
namespace Wabbajack.Downloaders.MediaFire;
|
|
|
|
|
|
2022-06-08 03:48:13 +00:00
|
|
|
|
public class MediaFireDownloader : ADownloader<DTOs.DownloadStates.MediaFire>, IUrlDownloader, IProxyable
|
2021-09-27 12:42:46 +00:00
|
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
|
private readonly IHttpDownloader _downloader;
|
|
|
|
|
private readonly HttpClient _httpClient;
|
|
|
|
|
private readonly ILogger<MediaFireDownloader> _logger;
|
|
|
|
|
|
|
|
|
|
public MediaFireDownloader(ILogger<MediaFireDownloader> logger, HttpClient httpClient, IHttpDownloader downloader)
|
2021-09-27 12:42:46 +00:00
|
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
|
_logger = logger;
|
|
|
|
|
_httpClient = httpClient;
|
|
|
|
|
_downloader = downloader;
|
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public override Task<bool> Prepare()
|
|
|
|
|
{
|
|
|
|
|
return Task.FromResult(true);
|
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public override bool IsAllowed(ServerAllowList allowList, IDownloadState state)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public override IDownloadState? Resolve(IReadOnlyDictionary<string, string> iniData)
|
|
|
|
|
{
|
|
|
|
|
if (iniData.ContainsKey("directURL") &&
|
2022-08-21 20:23:11 +00:00
|
|
|
|
Uri.TryCreate(iniData["directURL"].CleanIniString(), UriKind.Absolute, out var uri)
|
2021-10-23 16:51:17 +00:00
|
|
|
|
&& uri.Host == "www.mediafire.com")
|
2021-09-27 12:42:46 +00:00
|
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
|
var state = new DTOs.DownloadStates.MediaFire
|
|
|
|
|
{
|
|
|
|
|
Url = uri
|
|
|
|
|
};
|
|
|
|
|
return state;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
return null;
|
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public override Priority Priority => Priority.Normal;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public IDownloadState? Parse(Uri uri)
|
|
|
|
|
{
|
|
|
|
|
if (uri.Host != "www.mediafire.com")
|
2021-09-27 12:42:46 +00:00
|
|
|
|
return null;
|
2021-10-23 16:51:17 +00:00
|
|
|
|
return new DTOs.DownloadStates.MediaFire {Url = uri};
|
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public Uri UnParse(IDownloadState state)
|
|
|
|
|
{
|
|
|
|
|
return ((DTOs.DownloadStates.MediaFire) state).Url;
|
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
2022-06-08 13:12:44 +00:00
|
|
|
|
public async Task<T> DownloadStream<T>(Archive archive, Func<Stream, Task<T>> fn, CancellationToken token)
|
|
|
|
|
{
|
|
|
|
|
var state = archive.State as DTOs.DownloadStates.MediaFire;
|
|
|
|
|
var url = await Resolve(state!);
|
|
|
|
|
var msg = new HttpRequestMessage(HttpMethod.Get, url!);
|
|
|
|
|
using var result = await _httpClient.SendAsync(msg, token);
|
|
|
|
|
await using var stream = await result.Content.ReadAsStreamAsync(token);
|
|
|
|
|
return await fn(stream);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public override async Task<Hash> Download(Archive archive, DTOs.DownloadStates.MediaFire state,
|
|
|
|
|
AbsolutePath destination, IJob job, CancellationToken token)
|
|
|
|
|
{
|
|
|
|
|
var url = await Resolve(state, job);
|
|
|
|
|
var msg = new HttpRequestMessage(HttpMethod.Get, url!);
|
|
|
|
|
return await _downloader.Download(msg, destination, job, token);
|
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public override async Task<bool> Verify(Archive archive, DTOs.DownloadStates.MediaFire archiveState, IJob job,
|
|
|
|
|
CancellationToken token)
|
|
|
|
|
{
|
|
|
|
|
return await Resolve(archiveState, job, token) != null;
|
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
2022-06-08 13:12:44 +00:00
|
|
|
|
private async Task<Uri?> Resolve(DTOs.DownloadStates.MediaFire state, IJob? job = null, CancellationToken? token = null)
|
2021-10-23 16:51:17 +00:00
|
|
|
|
{
|
|
|
|
|
token ??= CancellationToken.None;
|
|
|
|
|
using var result = await _httpClient.GetAsync(state.Url, HttpCompletionOption.ResponseHeadersRead,
|
|
|
|
|
(CancellationToken) token);
|
|
|
|
|
if (!result.IsSuccessStatusCode)
|
|
|
|
|
return null;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
2022-06-08 13:12:44 +00:00
|
|
|
|
if (job != null)
|
|
|
|
|
job.Size = result.Content.Headers.ContentLength ?? 0;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
if (result.Content.Headers.ContentType!.MediaType!.StartsWith("text/html",
|
|
|
|
|
StringComparison.OrdinalIgnoreCase))
|
2021-09-27 12:42:46 +00:00
|
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
|
var bodyData = await result.Content.ReadAsStringAsync((CancellationToken) token);
|
2022-06-09 20:54:41 +00:00
|
|
|
|
if (job != null)
|
2022-10-07 22:14:01 +00:00
|
|
|
|
await job.Report((int) (job.Size ?? 0), (CancellationToken) token);
|
2021-10-23 16:51:17 +00:00
|
|
|
|
var body = new HtmlDocument();
|
|
|
|
|
body.LoadHtml(bodyData);
|
2022-08-09 23:41:11 +00:00
|
|
|
|
var node = body.DocumentNode.DescendantsAndSelf().FirstOrDefault(d => d.HasClass("input") && d.HasClass("popsok") &&
|
2021-10-23 16:51:17 +00:00
|
|
|
|
d.GetAttributeValue("aria-label", "") ==
|
|
|
|
|
"Download file");
|
2022-08-09 23:41:11 +00:00
|
|
|
|
if (node != null)
|
|
|
|
|
return new Uri(node.GetAttributeValue("href", "not-found"));
|
|
|
|
|
|
|
|
|
|
var startText = "window.location.href = '";
|
|
|
|
|
var start = body.DocumentNode.InnerHtml.IndexOf(startText, StringComparison.CurrentCultureIgnoreCase);
|
|
|
|
|
|
|
|
|
|
if (start != -1)
|
|
|
|
|
{
|
|
|
|
|
var end = body.DocumentNode.InnerHtml.IndexOf("\'", start + startText.Length,
|
|
|
|
|
StringComparison.CurrentCultureIgnoreCase);
|
|
|
|
|
var data = body.DocumentNode.InnerHtml[(start + startText.Length)..end];
|
|
|
|
|
return new Uri(data);
|
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
}
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
|
|
return state.Url;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public override IEnumerable<string> MetaIni(Archive a, DTOs.DownloadStates.MediaFire state)
|
|
|
|
|
{
|
|
|
|
|
return new[] {$"directURL={state.Url}"};
|
|
|
|
|
}
|
|
|
|
|
}
|