2020-01-01 16:19:06 +00:00
|
|
|
|
using System;
|
2020-01-03 22:15:55 +00:00
|
|
|
|
using System.Linq;
|
2019-12-06 05:29:17 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2020-01-03 22:15:55 +00:00
|
|
|
|
using HtmlAgilityPack;
|
2020-04-06 20:48:54 +00:00
|
|
|
|
using Newtonsoft.Json;
|
2019-10-12 22:31:07 +00:00
|
|
|
|
using Wabbajack.Common;
|
2020-04-06 20:48:54 +00:00
|
|
|
|
using Wabbajack.Common.Serialization.Json;
|
2019-10-16 03:10:34 +00:00
|
|
|
|
using Wabbajack.Lib.Validation;
|
2019-10-12 22:31:07 +00:00
|
|
|
|
|
2019-10-16 03:10:34 +00:00
|
|
|
|
namespace Wabbajack.Lib.Downloaders
|
2019-10-12 22:31:07 +00:00
|
|
|
|
{
|
2019-10-16 11:44:45 +00:00
|
|
|
|
public class ModDBDownloader : IDownloader, IUrlDownloader
|
2019-10-12 22:31:07 +00:00
|
|
|
|
{
|
2020-04-03 03:57:59 +00:00
|
|
|
|
public async Task<AbstractDownloadState> GetDownloaderState(dynamic archiveINI, bool quickMode)
|
2019-10-12 22:31:07 +00:00
|
|
|
|
{
|
2019-11-21 15:51:57 +00:00
|
|
|
|
var url = archiveINI?.General?.directURL;
|
2019-10-16 11:44:45 +00:00
|
|
|
|
return GetDownloaderState(url);
|
|
|
|
|
}
|
2019-10-12 22:31:07 +00:00
|
|
|
|
|
2019-10-16 11:44:45 +00:00
|
|
|
|
public AbstractDownloadState GetDownloaderState(string url)
|
|
|
|
|
{
|
2019-10-12 22:31:07 +00:00
|
|
|
|
if (url != null && url.StartsWith("https://www.moddb.com/downloads/start"))
|
|
|
|
|
{
|
|
|
|
|
return new State
|
|
|
|
|
{
|
2020-02-02 12:15:29 +00:00
|
|
|
|
Url = url
|
2019-10-12 22:31:07 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-07 02:45:13 +00:00
|
|
|
|
public async Task Prepare()
|
2019-10-12 22:31:07 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("ModDBDownloader")]
|
2019-10-12 22:31:07 +00:00
|
|
|
|
public class State : AbstractDownloadState
|
|
|
|
|
{
|
2020-02-02 12:15:29 +00:00
|
|
|
|
public string Url { get; set; }
|
2020-03-26 23:02:15 +00:00
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonIgnore]
|
2020-02-02 12:15:29 +00:00
|
|
|
|
public override object[] PrimaryKey { get => new object[]{Url}; }
|
2020-01-01 16:19:06 +00:00
|
|
|
|
|
2019-10-12 22:31:07 +00:00
|
|
|
|
public override bool IsWhitelisted(ServerWhitelist whitelist)
|
|
|
|
|
{
|
|
|
|
|
// Everything from Moddb is whitelisted
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 22:30:43 +00:00
|
|
|
|
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
2019-10-12 22:31:07 +00:00
|
|
|
|
{
|
2020-01-03 22:15:55 +00:00
|
|
|
|
var urls = await GetDownloadUrls();
|
|
|
|
|
Utils.Log($"Found {urls.Length} ModDB mirrors for {a.Name}");
|
2020-01-18 19:57:26 +00:00
|
|
|
|
foreach (var (url, idx) in urls.Zip(Enumerable.Range(0, urls.Length), (s, i) => (s, i)))
|
|
|
|
|
{
|
2020-01-03 22:15:55 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
2020-02-02 12:15:29 +00:00
|
|
|
|
await new HTTPDownloader.State {Url = url}.Download(a, destination);
|
2020-01-18 19:57:26 +00:00
|
|
|
|
return true;
|
2020-01-03 22:15:55 +00:00
|
|
|
|
}
|
2020-01-18 19:57:26 +00:00
|
|
|
|
catch (Exception)
|
2020-01-03 22:15:55 +00:00
|
|
|
|
{
|
|
|
|
|
if (idx == urls.Length - 1)
|
|
|
|
|
throw;
|
|
|
|
|
Utils.Log($"Download from {url} failed, trying next mirror");
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-18 19:57:26 +00:00
|
|
|
|
return false;
|
2019-10-12 22:31:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-03 22:15:55 +00:00
|
|
|
|
private async Task<string[]> GetDownloadUrls()
|
2019-10-12 22:31:07 +00:00
|
|
|
|
{
|
2020-02-02 12:15:29 +00:00
|
|
|
|
var uri = new Uri(Url);
|
2020-01-03 22:15:55 +00:00
|
|
|
|
var modId = uri.AbsolutePath.Split('/').Reverse().First(f => int.TryParse(f, out int _));
|
|
|
|
|
var mirrorUrl = $"https://www.moddb.com/downloads/start/{modId}/all";
|
|
|
|
|
var doc = await new HtmlWeb().LoadFromWebAsync($"https://www.moddb.com/downloads/start/{modId}/all");
|
|
|
|
|
var mirrors = doc.DocumentNode.Descendants().Where(d => d.NodeType == HtmlNodeType.Element && d.HasClass("row"))
|
|
|
|
|
.Select(d => new
|
|
|
|
|
{
|
|
|
|
|
Link = "https://www.moddb.com"+
|
|
|
|
|
d.Descendants().Where(s => s.Id == "downloadon")
|
|
|
|
|
.Select(i => i.GetAttributeValue("href", ""))
|
|
|
|
|
.FirstOrDefault(),
|
|
|
|
|
Load = d.Descendants().Where(s => s.HasClass("subheading"))
|
|
|
|
|
.Select(i => i.InnerHtml.Split(',')
|
|
|
|
|
.Last()
|
|
|
|
|
.Split('%')
|
|
|
|
|
.Select(v => double.TryParse(v, out var dr) ? dr : double.MaxValue)
|
|
|
|
|
.First())
|
|
|
|
|
.FirstOrDefault()
|
|
|
|
|
})
|
|
|
|
|
.OrderBy(d => d.Load)
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
return mirrors.Select(d => d.Link).ToArray();
|
2019-10-12 22:31:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-13 22:55:55 +00:00
|
|
|
|
public override async Task<bool> Verify(Archive a)
|
2019-10-12 22:31:07 +00:00
|
|
|
|
{
|
2020-01-03 22:15:55 +00:00
|
|
|
|
await GetDownloadUrls();
|
|
|
|
|
return true;
|
2019-10-12 22:31:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override IDownloader GetDownloader()
|
|
|
|
|
{
|
|
|
|
|
return DownloadDispatcher.GetInstance<ModDBDownloader>();
|
|
|
|
|
}
|
2019-10-12 22:54:25 +00:00
|
|
|
|
|
2020-02-02 12:23:07 +00:00
|
|
|
|
public override string GetManifestURL(Archive a)
|
2020-02-02 12:15:29 +00:00
|
|
|
|
{
|
2020-02-02 12:23:07 +00:00
|
|
|
|
return Url;
|
2020-02-02 12:15:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-11 04:15:53 +00:00
|
|
|
|
public override string[] GetMetaIni()
|
|
|
|
|
{
|
2020-02-02 12:15:29 +00:00
|
|
|
|
return new[] {"[General]", $"directURL={Url}"};
|
2020-01-11 04:15:53 +00:00
|
|
|
|
}
|
2019-10-12 22:31:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|