From e51e90aabc12d7f1fb6c8a69d7e2e953b9e99f64 Mon Sep 17 00:00:00 2001 From: glax Date: Tue, 17 Jun 2025 00:23:38 +0200 Subject: [PATCH] FlareSolverr by FlareSolverrSharp #372 --- API/API.csproj | 1 + API/Controllers/SettingsController.cs | 71 ++++++++++++++++++- .../HttpDownloadClient.cs | 23 +++--- API/TrangaSettings.cs | 10 +++ README.md | 3 +- 5 files changed, 92 insertions(+), 16 deletions(-) diff --git a/API/API.csproj b/API/API.csproj index 24d1e9c..6453ad5 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -11,6 +11,7 @@ + diff --git a/API/Controllers/SettingsController.cs b/API/Controllers/SettingsController.cs index 2e3dff2..39233f7 100644 --- a/API/Controllers/SettingsController.cs +++ b/API/Controllers/SettingsController.cs @@ -1,10 +1,13 @@ -using API.MangaDownloadClients; +using System.Net.Http.Headers; +using API.MangaDownloadClients; using API.Schema; using API.Schema.Contexts; using API.Schema.Jobs; using Asp.Versioning; +using FlareSolverrSharp; using log4net; using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using static Microsoft.AspNetCore.Http.StatusCodes; @@ -291,4 +294,70 @@ public class SettingsController(PgsqlContext context, ILog Log) : Controller return StatusCode(500, e); } } + + /// + /// Sets the FlareSolverr-URL + /// + /// URL of FlareSolverr-Instance + /// + [HttpPost("FlareSolverr/Url")] + [ProducesResponseType(Status200OK)] + public IActionResult SetFlareSolverrUrl([FromBody]string flareSolverrUrl) + { + TrangaSettings.UpdateFlareSolverrUrl(flareSolverrUrl); + return Ok(); + } + + /// + /// Resets the FlareSolverr-URL (HttpClient does not use FlareSolverr anymore) + /// + /// + [HttpDelete("FlareSolverr/Url")] + [ProducesResponseType(Status200OK)] + public IActionResult ClearFlareSolverrUrl() + { + TrangaSettings.UpdateFlareSolverrUrl(string.Empty); + return Ok(); + } + + /// + /// + /// + /// FlareSolverr is working! + /// FlareSolverr URL is malformed + /// FlareSolverr is not working + /// FlareSolverr could not be reached + [HttpPost("FlareSolverr/Test")] + [ProducesResponseType(Status200OK)] + [ProducesResponseType(Status400BadRequest)] + [ProducesResponseType(Status500InternalServerError)] + [ProducesResponseType(Status503ServiceUnavailable)] + public IActionResult TestFlareSolverrReachable() + { + const string knownProtectedUrl = "https://prowlarr.servarr.com/v1/ping"; + HttpClient client = new(); + if (!Uri.TryCreate(new(TrangaSettings.flareSolverrUrl), "v1", out Uri? uri)) + return BadRequest(); + HttpRequestMessage request = new(HttpMethod.Post, uri); + JObject data = new() + { + ["cmd"] = "request.get", + ["url"] = knownProtectedUrl + }; + request.Content = new StringContent(JsonConvert.SerializeObject(data)); + request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); + HttpResponseMessage response = client.Send(request); + if (!response.IsSuccessStatusCode) + return StatusCode(Status503ServiceUnavailable); + client = new(new ClearanceHandler(TrangaSettings.flareSolverrUrl)); + try + { + client.GetStringAsync(knownProtectedUrl).Wait(); + return Ok(); + } + catch (Exception e) + { + return StatusCode(Status500InternalServerError); + } + } } \ No newline at end of file diff --git a/API/MangaDownloadClients/HttpDownloadClient.cs b/API/MangaDownloadClients/HttpDownloadClient.cs index 5bf42c4..cf9bedf 100644 --- a/API/MangaDownloadClients/HttpDownloadClient.cs +++ b/API/MangaDownloadClients/HttpDownloadClient.cs @@ -1,27 +1,22 @@ using System.Net; +using FlareSolverrSharp; using HtmlAgilityPack; namespace API.MangaDownloadClients; internal class HttpDownloadClient : DownloadClient { - private static readonly HttpClient Client = new() - { - Timeout = TimeSpan.FromSeconds(10), - DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrHigher - }; - - public HttpDownloadClient() - { - if(Client.DefaultRequestHeaders.UserAgent.Count < 1) - Client.DefaultRequestHeaders.UserAgent.ParseAdd(TrangaSettings.userAgent); - } - internal override RequestResult MakeRequestInternal(string url, string? referrer = null, string? clickButton = null) { if (clickButton is not null) Log.Warn("Client can not click button"); - HttpResponseMessage? response = null; + HttpClient client = TrangaSettings.flareSolverrUrl == string.Empty + ? new () + : new (new ClearanceHandler(TrangaSettings.flareSolverrUrl)); + client.Timeout = TimeSpan.FromSeconds(10); + client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrHigher; + client.DefaultRequestHeaders.Add("User-Agent", TrangaSettings.userAgent); + HttpResponseMessage? response; Uri uri = new(url); HttpRequestMessage requestMessage = new(HttpMethod.Get, uri); if (referrer is not null) @@ -29,7 +24,7 @@ internal class HttpDownloadClient : DownloadClient Log.Debug($"Requesting {url}"); try { - response = Client.Send(requestMessage); + response = client.Send(requestMessage); } catch (HttpRequestException e) { diff --git a/API/TrangaSettings.cs b/API/TrangaSettings.cs index 39228c0..fdc766e 100644 --- a/API/TrangaSettings.cs +++ b/API/TrangaSettings.cs @@ -15,6 +15,7 @@ public static class TrangaSettings public static string userAgent { get; private set; } = DefaultUserAgent; public static int compression{ get; private set; } = 40; public static bool bwImages { get; private set; } = false; + public static string flareSolverrUrl { get; private set; } = string.Empty; /// /// Placeholders: /// %M Manga Name @@ -102,6 +103,12 @@ public static class TrangaSettings ExportSettings(); } + public static void UpdateFlareSolverrUrl(string url) + { + flareSolverrUrl = url; + ExportSettings(); + } + public static void ResetRequestLimits() { requestLimits = DefaultRequestLimits; @@ -148,6 +155,7 @@ public static class TrangaSettings jobj.Add("bwImages", JToken.FromObject(bwImages)); jobj.Add("startNewJobTimeoutMs", JToken.FromObject(startNewJobTimeoutMs)); jobj.Add("chapterNamingScheme", JToken.FromObject(chapterNamingScheme)); + jobj.Add("flareSolverrUrl", JToken.FromObject(flareSolverrUrl)); return jobj; } @@ -174,5 +182,7 @@ public static class TrangaSettings startNewJobTimeoutMs = snjt.Value()!; if (jobj.TryGetValue("chapterNamingScheme", out JToken? cns)) chapterNamingScheme = cns.Value()!; + if (jobj.TryGetValue("flareSolverrUrl", out JToken? fsu)) + flareSolverrUrl = fsu.Value()!; } } \ No newline at end of file diff --git a/README.md b/README.md index 0994c4a..0120c11 100644 --- a/README.md +++ b/README.md @@ -86,12 +86,13 @@ Endpoints are documented in Swagger. Just spin up an instance, and go to `http:/ - .NET - ASP.NET - - Entity Framework + - Entity Framework Core - [PostgreSQL](https://www.postgresql.org/about/licence/) - [Swagger](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/LICENSE) - [Ngpsql](https://github.com/npgsql/npgsql/blob/main/LICENSE) - [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json/blob/master/LICENSE.md) - [PuppeteerSharp](https://github.com/hardkoded/puppeteer-sharp/blob/master/LICENSE) +- [FlareSolverrSharp](https://github.com/FlareSolverr/FlareSolverrSharp) - [Html Agility Pack (HAP)](https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE) - [Soenneker.Utils.String.NeedlemanWunsch](https://github.com/soenneker/soenneker.utils.string.needlemanwunsch/blob/main/LICENSE) - [Sixlabors.ImageSharp](https://docs-v2.sixlabors.com/articles/imagesharp/index.html#license)