From d80eac139ffc1079a90d33f9e78f6500f677f411 Mon Sep 17 00:00:00 2001 From: baliasnyifeliks Date: Tue, 3 Feb 2026 19:37:54 +0200 Subject: [PATCH] feat(makhno): add APN helper for URL proxying Add ApnHelper class to handle APN configuration and URL wrapping functionality. This includes methods for parsing configuration, applying settings, detecting specific domains, and building proxied URLs with proper encoding. Also fix regex patterns in MakhnoInvoke to correctly match URLs with double quotes. --- .gitignore | 3 +- Makhno/ApnHelper.cs | 86 ++++++++++++++++++++++++++++++++++++++++++ Makhno/MakhnoInvoke.cs | 10 ++--- 3 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 Makhno/ApnHelper.cs diff --git a/.gitignore b/.gitignore index aa69327..1032ed8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ /.clinerules/moduls.md /.clinerules/uaflix-optimization.md /.clinerules/ -/.qodo/ \ No newline at end of file +/.qodo/ +.DS_Store diff --git a/Makhno/ApnHelper.cs b/Makhno/ApnHelper.cs new file mode 100644 index 0000000..394a5bc --- /dev/null +++ b/Makhno/ApnHelper.cs @@ -0,0 +1,86 @@ +using Newtonsoft.Json.Linq; +using Shared.Models.Base; +using System; +using System.Web; + +namespace Shared.Engine +{ + public static class ApnHelper + { + public const string DefaultHost = "https://tut.im/proxy.php?url={encodeurl}"; + + public static bool TryGetInitConf(JObject conf, out bool enabled, out string host) + { + enabled = false; + host = null; + + if (conf == null) + return false; + + if (!conf.TryGetValue("apn", out var apnToken) || apnToken?.Type != JTokenType.Boolean) + return false; + + enabled = apnToken.Value(); + host = conf.Value("apn_host"); + return true; + } + + public static void ApplyInitConf(bool enabled, string host, BaseSettings init) + { + if (init == null) + return; + + if (!enabled) + { + init.apnstream = false; + init.apn = null; + return; + } + + if (string.IsNullOrWhiteSpace(host)) + host = DefaultHost; + + if (init.apn == null) + init.apn = new ApnConf(); + + init.apn.host = host; + init.apnstream = true; + } + + public static bool IsEnabled(BaseSettings init) + { + return init?.apnstream == true && !string.IsNullOrWhiteSpace(init?.apn?.host); + } + + public static bool IsAshdiUrl(string url) + { + return !string.IsNullOrEmpty(url) && + url.IndexOf("ashdi.vip", StringComparison.OrdinalIgnoreCase) >= 0; + } + + public static string WrapUrl(BaseSettings init, string url) + { + if (!IsEnabled(init)) + return url; + + return BuildUrl(init.apn.host, url); + } + + public static string BuildUrl(string host, string url) + { + if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(url)) + return url; + + if (host.Contains("{encodeurl}")) + return host.Replace("{encodeurl}", HttpUtility.UrlEncode(url)); + + if (host.Contains("{encode_uri}")) + return host.Replace("{encode_uri}", HttpUtility.UrlEncode(url)); + + if (host.Contains("{uri}")) + return host.Replace("{uri}", url); + + return $"{host.TrimEnd('/')}/{url}"; + } + } +} diff --git a/Makhno/MakhnoInvoke.cs b/Makhno/MakhnoInvoke.cs index c70513f..7f75b28 100644 --- a/Makhno/MakhnoInvoke.cs +++ b/Makhno/MakhnoInvoke.cs @@ -170,7 +170,7 @@ namespace Makhno return NormalizePlayerUrl(src); } - var urlMatch = Regex.Match(moviePageContent, @"(https?://[^\"'\s>]+/(?:vod|serial)/\d+[^\"'\s>]*)", RegexOptions.IgnoreCase); + var urlMatch = Regex.Match(moviePageContent, @"(https?://[^""'\s>]+/(?:vod|serial)/\d+[^""'\s>]*)", RegexOptions.IgnoreCase); if (urlMatch.Success) return NormalizePlayerUrl(urlMatch.Groups[1].Value); @@ -239,11 +239,11 @@ namespace Makhno var fileMatch = Regex.Match(html, @"file:'([^']+)'", RegexOptions.IgnoreCase); if (!fileMatch.Success) - fileMatch = Regex.Match(html, @"file:\s*\"([^\"]+)\"", RegexOptions.IgnoreCase); + fileMatch = Regex.Match(html, @"file:\s*""([^""]+)""", RegexOptions.IgnoreCase); if (fileMatch.Success && !fileMatch.Groups[1].Value.StartsWith("[")) { - var posterMatch = Regex.Match(html, @"poster:[\"']([^\"']+)[\"']", RegexOptions.IgnoreCase); + var posterMatch = Regex.Match(html, @"poster:[""']([^""']+)[""']", RegexOptions.IgnoreCase); return new PlayerData { File = fileMatch.Groups[1].Value, @@ -252,7 +252,7 @@ namespace Makhno }; } - var m3u8Match = Regex.Match(html, @"(https?://[^\"'\s>]+\.m3u8[^\"'\s>]*)", RegexOptions.IgnoreCase); + var m3u8Match = Regex.Match(html, @"(https?://[^""'\s>]+\.m3u8[^""'\s>]*)", RegexOptions.IgnoreCase); if (m3u8Match.Success) { return new PlayerData @@ -263,7 +263,7 @@ namespace Makhno }; } - var sourceMatch = Regex.Match(html, @"]*src=[\"']([^\"']+)[\"']", RegexOptions.IgnoreCase); + var sourceMatch = Regex.Match(html, @"]*src=[""']([^""']+)[""']", RegexOptions.IgnoreCase); if (sourceMatch.Success) { return new PlayerData