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.
This commit is contained in:
baliasnyifeliks 2026-02-03 19:37:54 +02:00
parent 5f40e1781f
commit d80eac139f
3 changed files with 93 additions and 6 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@
/.clinerules/uaflix-optimization.md /.clinerules/uaflix-optimization.md
/.clinerules/ /.clinerules/
/.qodo/ /.qodo/
.DS_Store

86
Makhno/ApnHelper.cs Normal file
View File

@ -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<bool>();
host = conf.Value<string>("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}";
}
}
}

View File

@ -170,7 +170,7 @@ namespace Makhno
return NormalizePlayerUrl(src); 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) if (urlMatch.Success)
return NormalizePlayerUrl(urlMatch.Groups[1].Value); return NormalizePlayerUrl(urlMatch.Groups[1].Value);
@ -239,11 +239,11 @@ namespace Makhno
var fileMatch = Regex.Match(html, @"file:'([^']+)'", RegexOptions.IgnoreCase); var fileMatch = Regex.Match(html, @"file:'([^']+)'", RegexOptions.IgnoreCase);
if (!fileMatch.Success) 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("[")) 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 return new PlayerData
{ {
File = fileMatch.Groups[1].Value, 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) if (m3u8Match.Success)
{ {
return new PlayerData return new PlayerData
@ -263,7 +263,7 @@ namespace Makhno
}; };
} }
var sourceMatch = Regex.Match(html, @"<source[^>]*src=[\"']([^\"']+)[\"']", RegexOptions.IgnoreCase); var sourceMatch = Regex.Match(html, @"<source[^>]*src=[""']([^""']+)[""']", RegexOptions.IgnoreCase);
if (sourceMatch.Success) if (sourceMatch.Success)
{ {
return new PlayerData return new PlayerData