wabbajack/Wabbajack.Downloaders.MediaFire/MediaFireDownloader.cs

146 lines
5.3 KiB
C#
Raw Normal View History

2021-09-27 12:42:46 +00:00
using System;
using System.Collections.Generic;
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;
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;
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)
{
var mediaFireState = (DTOs.DownloadStates.MediaFire) state;
return allowList.AllowedPrefixes.Any(p => mediaFireState.Url.ToString().StartsWith(p, StringComparison.OrdinalIgnoreCase));
2021-10-23 16:51:17 +00:00
}
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") &&
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
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
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
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);
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");
if (node != null)
2022-08-09 23:41:11 +00:00
return new Uri(node.GetAttributeValue("href", "not-found"));
2022-08-09 23:41:11 +00:00
var startText = "window.location.href = '";
var start = body.DocumentNode.InnerHtml.IndexOf(startText, StringComparison.CurrentCultureIgnoreCase);
2022-08-09 23:41:11 +00:00
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}"};
}
}