Merge pull request #19 from lampame/uaflix-auth

Uaflix auth
This commit is contained in:
Felix 2026-02-22 11:07:29 +02:00 committed by GitHub
commit 1c49df634a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 508 additions and 65 deletions

View File

@ -62,6 +62,9 @@ modules - optional, if not specified, all modules from the repository will be in
"enable": true,
"domain": "https://uaflix.net",
"displayname": "Uaflix",
"login": null,
"passwd": null,
"cookie": null,
"webcorshost": null,
"streamproxy": false,
"useproxy": false,

View File

@ -18,7 +18,7 @@ using Uaflix.Models;
namespace Uaflix.Controllers
{
public class Controller : BaseOnlineController
public class Controller : BaseOnlineController<UaflixSettings>
{
ProxyManager proxyManager;
@ -42,7 +42,8 @@ namespace Uaflix.Controllers
OnLog($"Uaflix Index: kinopoisk_id={kinopoisk_id}, imdb_id={imdb_id}, id={id}");
OnLog($"Uaflix Index: year={year}, source={source}, t={t}, e={e}, rjson={rjson}");
var invoke = new UaflixInvoke(init, hybridCache, OnLog, proxyManager);
var auth = new UaflixAuth(init, memoryCache, OnLog, proxyManager);
var invoke = new UaflixInvoke(init, hybridCache, OnLog, proxyManager, auth);
// Обробка параметра checksearch - повертаємо спеціальну відповідь для валідації
if (checksearch)
@ -52,32 +53,21 @@ namespace Uaflix.Controllers
try
{
string filmTitle = !string.IsNullOrEmpty(title) ? title : original_title;
string searchUrl = $"{init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(filmTitle)}";
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) };
var searchHtml = await Http.Get(init.cors(searchUrl), headers: headers, proxy: proxyManager.Get(), timeoutSeconds: 10);
// Швидка перевірка наявності результатів без повного парсингу
if (!string.IsNullOrEmpty(searchHtml) &&
(searchHtml.Contains("sres-wrap") || searchHtml.Contains("sres-item") || searchHtml.Contains("search-results")))
bool hasContent = await invoke.CheckSearchAvailability(title, original_title);
if (hasContent)
{
// Якщо знайдено контент, повертаємо "data-json=" для валідації
OnLog("checksearch: Content found, returning validation response");
OnLog("checksearch: Контент знайдено, повертаю валідаційний маркер");
OnLog("=== RETURN: checksearch validation (data-json=) ===");
return Content("data-json=", "text/plain; charset=utf-8");
}
else
{
// Якщо нічого не знайдено, повертаємо OnError
OnLog("checksearch: No content found");
OnLog("checksearch: Контент не знайдено");
OnLog("=== RETURN: checksearch OnError ===");
return OnError("uaflix", proxyManager);
}
}
catch (Exception ex)
{
OnLog($"checksearch error: {ex.Message}");
OnLog($"checksearch: помилка - {ex.Message}");
OnLog("=== RETURN: checksearch exception OnError ===");
return OnError("uaflix", proxyManager);
}

View File

@ -1,72 +1,67 @@
using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Shared;
using Shared.Engine;
using Newtonsoft.Json.Linq;
using Shared.Models.Online.Settings;
using Shared.Models.Module;
using Microsoft.AspNetCore.Mvc;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using Shared.Models;
using Shared.Models.Events;
using System;
using System.Net.Http;
using System.Net.Mime;
using System.Net.Security;
using System.Security.Authentication;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Uaflix.Models;
namespace Uaflix
{
public class ModInit
{
public static double Version => 3.8;
public static double Version => 4.0;
public static UaflixSettings UaFlix;
public static OnlinesSettings UaFlix;
public static bool ApnHostProvided;
public static OnlinesSettings Settings
public static UaflixSettings Settings
{
get => UaFlix;
set => UaFlix = value;
}
/// <summary>
/// модуль загружен
/// Модуль завантажено.
/// </summary>
public static void loaded(InitspaceModel initspace)
{
UaFlix = new OnlinesSettings("Uaflix", "https://uafix.net", streamproxy: false, useproxy: false)
UaFlix = new UaflixSettings("Uaflix", "https://uafix.net", streamproxy: false, useproxy: false)
{
displayname = "UaFlix",
group = 0,
group_hide = false,
globalnameproxy = null,
displayindex = 0,
login = null,
passwd = null,
proxy = new Shared.Models.Base.ProxySettings()
{
useAuth = true,
username = "a",
password = "a",
list = new string[] { "socks5://IP:PORT" }
},
// Note: OnlinesSettings не має властивості additional, використовуємо інший підхід
}
};
var conf = ModuleInvoke.Conf("Uaflix", UaFlix);
var conf = ModuleInvoke.Conf("Uaflix", UaFlix) ?? JObject.FromObject(UaFlix);
bool hasApn = ApnHelper.TryGetInitConf(conf, out bool apnEnabled, out string apnHost);
conf.Remove("apn");
conf.Remove("apn_host");
UaFlix = conf.ToObject<OnlinesSettings>();
UaFlix = conf.ToObject<UaflixSettings>();
if (hasApn)
ApnHelper.ApplyInitConf(apnEnabled, apnHost, UaFlix);
ApnHostProvided = hasApn && apnEnabled && !string.IsNullOrWhiteSpace(apnHost);
if (hasApn && apnEnabled)
{
@ -78,7 +73,7 @@ namespace Uaflix
UaFlix.apn = null;
}
// Виводити "уточнити пошук"
// Показувати «уточнити пошук».
AppInit.conf.online.with_search.Add("uaflix");
}
}
@ -186,6 +181,7 @@ namespace Uaflix
_resetTimer = null;
}
}
public static bool IsDisconnected()
{
return _disconnectTime is not null

View File

@ -0,0 +1,27 @@
using System;
using Shared.Models.Online.Settings;
namespace Uaflix.Models
{
public class UaflixSettings : OnlinesSettings, ICloneable
{
public UaflixSettings(string plugin, string host, string apihost = null, bool useproxy = false, string token = null, bool enable = true, bool streamproxy = false, bool rip = false, bool forceEncryptToken = false, string rch_access = null, string stream_access = null)
: base(plugin, host, apihost, useproxy, token, enable, streamproxy, rip, forceEncryptToken, rch_access, stream_access)
{
}
public string login { get; set; }
public string passwd { get; set; }
public new UaflixSettings Clone()
{
return (UaflixSettings)MemberwiseClone();
}
object ICloneable.Clone()
{
return MemberwiseClone();
}
}
}

334
Uaflix/UaflixAuth.cs Normal file
View File

@ -0,0 +1,334 @@
using Shared.Engine;
using Shared.Models;
using Uaflix.Models;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace Uaflix
{
public sealed class UaflixAuth
{
private static readonly ConcurrentDictionary<string, CookieContainer> CookieContainers = new();
private static readonly ConcurrentDictionary<string, string> CookieHeaders = new();
private readonly UaflixSettings _init;
private readonly IMemoryCache _memoryCache;
private readonly Action<string> _onLog;
private readonly ProxyManager _proxyManager;
public UaflixAuth(UaflixSettings init, IMemoryCache memoryCache, Action<string> onLog, ProxyManager proxyManager)
{
_init = init;
_memoryCache = memoryCache;
_onLog = onLog;
_proxyManager = proxyManager;
}
public bool CanUseCredentials => !string.IsNullOrWhiteSpace(_init?.login) && !string.IsNullOrWhiteSpace(_init?.passwd);
public async ValueTask<string> GetCookieHeaderAsync(bool forceRefresh = false)
{
if (_init == null || string.IsNullOrWhiteSpace(_init.host))
return null;
Uri hostUri;
try
{
hostUri = new Uri(EnsureTrailingSlash(_init.host));
}
catch
{
_onLog("UaflixAuth: некоректний host у конфігурації");
return null;
}
string key = BuildAuthKey();
if (forceRefresh)
{
CookieHeaders.TryRemove(key, out _);
CookieContainers.TryRemove(key, out _);
}
if (CookieHeaders.TryGetValue(key, out string cachedCookie) && !string.IsNullOrWhiteSpace(cachedCookie))
return cachedCookie;
if (CookieContainers.TryGetValue(key, out CookieContainer cachedContainer))
{
string cookieFromContainer = BuildCookieHeader(cachedContainer, hostUri);
if (!string.IsNullOrWhiteSpace(cookieFromContainer))
{
CookieHeaders[key] = cookieFromContainer;
return cookieFromContainer;
}
}
if (!string.IsNullOrWhiteSpace(_init.cookie))
{
string normalized = NormalizeCookie(_init.cookie);
if (string.IsNullOrWhiteSpace(normalized))
return null;
var manualContainer = CreateContainerFromCookie(normalized);
CacheAuthState(key, normalized, manualContainer);
return normalized;
}
if (!CanUseCredentials)
return null;
string loginThrottleKey = $"uaflix:login:{_init.host}:{_init.login}";
if (!forceRefresh && _memoryCache.TryGetValue(loginThrottleKey, out _))
return null;
_memoryCache.Set(loginThrottleKey, 0, TimeSpan.FromSeconds(20));
var authResult = await LoginByCredentials();
if (!authResult.success || string.IsNullOrWhiteSpace(authResult.cookie))
return null;
CacheAuthState(key, authResult.cookie, authResult.container);
return authResult.cookie;
}
public void ApplyCookieHeader(List<HeadersModel> headers, string cookie)
{
if (headers == null || string.IsNullOrWhiteSpace(cookie))
return;
headers.RemoveAll(h => h.name.Equals("Cookie", StringComparison.OrdinalIgnoreCase));
headers.Add(new HeadersModel("Cookie", cookie));
}
private async Task<(bool success, string cookie, CookieContainer container)> LoginByCredentials()
{
try
{
string host = EnsureTrailingSlash(_init.host);
var hostUri = new Uri(host);
var container = new CookieContainer();
var headers = new List<HeadersModel>
{
new HeadersModel("User-Agent", "Mozilla/5.0"),
new HeadersModel("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"),
new HeadersModel("Referer", host),
new HeadersModel("Origin", _init.host),
new HeadersModel("Accept-Language", "uk-UA,uk;q=0.9")
};
var postParams = new Dictionary<string, string>
{
["login_name"] = _init.login,
["login_password"] = _init.passwd,
["login"] = "submit",
["login_not_save"] = "1"
};
using var postData = new FormUrlEncodedContent(postParams);
var response = await Http.BasePost(host, postData,
timeoutSeconds: 20,
headers: headers,
proxy: _proxyManager?.Get(),
cookieContainer: container,
statusCodeOK: false);
if (response.response == null)
{
_onLog("UaflixAuth: логін не вдався, немає HTTP-відповіді");
return (false, null, null);
}
string body = response.content ?? string.Empty;
bool hasAuthError = body.Contains("Помилка авторизації", StringComparison.OrdinalIgnoreCase)
|| body.Contains("Вхід на сайт не був проведений", StringComparison.OrdinalIgnoreCase);
string cookie = BuildCookieHeader(container, hostUri) ?? string.Empty;
bool hasSession = cookie.Contains("PHPSESSID=", StringComparison.OrdinalIgnoreCase);
bool hasDleAuthCookie = cookie.Contains("dle_newpm=", StringComparison.OrdinalIgnoreCase)
|| cookie.Contains("dle_user_id=", StringComparison.OrdinalIgnoreCase)
|| cookie.Contains("dle_password=", StringComparison.OrdinalIgnoreCase)
|| cookie.Contains("dle_hash=", StringComparison.OrdinalIgnoreCase);
if (response.response.Headers.TryGetValues("Set-Cookie", out IEnumerable<string> setCookies))
{
foreach (string line in setCookies)
{
if (string.IsNullOrWhiteSpace(line) || IsDeletedCookie(line))
continue;
TrySetCookie(container, hostUri, line);
}
cookie = BuildCookieHeader(container, hostUri) ?? string.Empty;
hasSession = cookie.Contains("PHPSESSID=", StringComparison.OrdinalIgnoreCase);
hasDleAuthCookie = cookie.Contains("dle_newpm=", StringComparison.OrdinalIgnoreCase)
|| cookie.Contains("dle_user_id=", StringComparison.OrdinalIgnoreCase)
|| cookie.Contains("dle_password=", StringComparison.OrdinalIgnoreCase)
|| cookie.Contains("dle_hash=", StringComparison.OrdinalIgnoreCase);
}
if (hasAuthError || !hasSession || !hasDleAuthCookie)
{
_onLog($"UaflixAuth: авторизація неуспішна, status={(int)response.response.StatusCode}");
return (false, null, null);
}
_onLog("UaflixAuth: авторизація успішна");
return (true, cookie, container);
}
catch (Exception ex)
{
_onLog($"UaflixAuth: помилка авторизації - {ex.Message}");
return (false, null, null);
}
}
private string BuildAuthKey()
{
string login = _init.login ?? string.Empty;
string manualCookie = _init.cookie ?? string.Empty;
return $"{_init.host}|{login}|{manualCookie}";
}
private void CacheAuthState(string key, string cookie, CookieContainer container)
{
if (!string.IsNullOrWhiteSpace(cookie))
CookieHeaders[key] = cookie;
if (container != null)
CookieContainers[key] = container;
}
private CookieContainer CreateContainerFromCookie(string cookie)
{
var container = new CookieContainer();
if (string.IsNullOrWhiteSpace(cookie))
return container;
Uri hostUri = new Uri(EnsureTrailingSlash(_init.host));
foreach (string part in cookie.Split(';'))
{
string row = part.Trim();
if (string.IsNullOrWhiteSpace(row) || !row.Contains('='))
continue;
string name = row[..row.IndexOf('=')].Trim();
string value = row[(row.IndexOf('=') + 1)..].Trim();
if (string.IsNullOrWhiteSpace(name))
continue;
TryAddCookie(container, hostUri.Host, name, value);
}
return container;
}
private static void TrySetCookie(CookieContainer container, Uri uri, string setCookieLine)
{
try
{
container.SetCookies(uri, setCookieLine);
}
catch
{
string raw = setCookieLine.Split(';')[0].Trim();
int eq = raw.IndexOf('=');
if (eq <= 0)
return;
string name = raw[..eq].Trim();
string value = raw[(eq + 1)..].Trim();
TryAddCookie(container, uri.Host, name, value);
}
}
private static void TryAddCookie(CookieContainer container, string host, string name, string value)
{
try
{
var cookie = new Cookie(name, value, "/", host)
{
HttpOnly = true,
Expires = name.Equals("PHPSESSID", StringComparison.OrdinalIgnoreCase)
? default(DateTime)
: DateTime.UtcNow.AddMonths(6)
};
container.Add(cookie);
}
catch
{
}
}
private static string BuildCookieHeader(CookieContainer container, Uri hostUri)
{
if (container == null)
return null;
var cookies = container.GetCookies(hostUri)
.Cast<Cookie>()
.Where(c => !string.IsNullOrWhiteSpace(c.Name) && !string.IsNullOrWhiteSpace(c.Value))
.Select(c => $"{c.Name}={c.Value}")
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
return cookies.Count == 0 ? null : string.Join("; ", cookies);
}
private static bool IsDeletedCookie(string line)
{
return line.Contains("=deleted;", StringComparison.OrdinalIgnoreCase)
|| line.Contains("Max-Age=0", StringComparison.OrdinalIgnoreCase)
|| line.Contains("expires=Thu, 01-Jan-1970", StringComparison.OrdinalIgnoreCase);
}
private static string NormalizeCookie(string cookie)
{
if (string.IsNullOrWhiteSpace(cookie))
return null;
var pairs = new List<string>();
var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (string part in cookie.Split(';'))
{
string row = part.Trim();
if (string.IsNullOrWhiteSpace(row) || !row.Contains('='))
continue;
int eq = row.IndexOf('=');
if (eq <= 0)
continue;
string name = row[..eq].Trim();
string value = row[(eq + 1)..].Trim();
if (string.IsNullOrWhiteSpace(name))
continue;
map[name] = value;
}
foreach (var kv in map)
pairs.Add($"{kv.Key}={kv.Value}");
return pairs.Count == 0 ? null : string.Join("; ", pairs);
}
private static string EnsureTrailingSlash(string url)
{
if (string.IsNullOrWhiteSpace(url))
return url;
return url.EndsWith('/') ? url : $"{url}/";
}
}
}

View File

@ -23,17 +23,19 @@ namespace Uaflix
private static readonly Regex Quality4kRegex = new Regex(@"(^|[^0-9])(2160p?)([^0-9]|$)|\b4k\b|\buhd\b", RegexOptions.IgnoreCase);
private static readonly Regex QualityFhdRegex = new Regex(@"(^|[^0-9])(1080p?)([^0-9]|$)|\bfhd\b", RegexOptions.IgnoreCase);
private OnlinesSettings _init;
private IHybridCache _hybridCache;
private Action<string> _onLog;
private ProxyManager _proxyManager;
private readonly UaflixSettings _init;
private readonly IHybridCache _hybridCache;
private readonly Action<string> _onLog;
private readonly ProxyManager _proxyManager;
private readonly UaflixAuth _auth;
public UaflixInvoke(OnlinesSettings init, IHybridCache hybridCache, Action<string> onLog, ProxyManager proxyManager)
public UaflixInvoke(UaflixSettings init, IHybridCache hybridCache, Action<string> onLog, ProxyManager proxyManager, UaflixAuth auth)
{
_init = init;
_hybridCache = hybridCache;
_onLog = onLog;
_proxyManager = proxyManager;
_auth = auth;
}
string AshdiRequestUrl(string url)
@ -47,6 +49,97 @@ namespace Uaflix
return ApnHelper.WrapUrl(_init, url);
}
public async Task<bool> CheckSearchAvailability(string title, string originalTitle)
{
string filmTitle = !string.IsNullOrWhiteSpace(title) ? title : originalTitle;
if (string.IsNullOrWhiteSpace(filmTitle))
return false;
string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(filmTitle)}";
var headers = new List<HeadersModel>()
{
new HeadersModel("User-Agent", "Mozilla/5.0"),
new HeadersModel("Referer", _init.host)
};
string searchHtml = await GetHtml(searchUrl, headers, timeoutSeconds: 10);
if (string.IsNullOrWhiteSpace(searchHtml))
return false;
return searchHtml.Contains("sres-wrap")
|| searchHtml.Contains("sres-item")
|| searchHtml.Contains("search-results");
}
async Task<string> GetHtml(string url, List<HeadersModel> headers, int timeoutSeconds = 15, bool retryOnUnauthorized = true)
{
if (string.IsNullOrWhiteSpace(url))
return null;
string requestUrl = _init.cors(url);
bool withAuth = ShouldUseAuth(url);
var requestHeaders = headers != null ? new List<HeadersModel>(headers) : new List<HeadersModel>();
if (withAuth && _auth != null)
{
string cookie = await _auth.GetCookieHeaderAsync();
_auth.ApplyCookieHeader(requestHeaders, cookie);
}
var response = await Http.BaseGet(requestUrl,
headers: requestHeaders,
timeoutSeconds: timeoutSeconds,
proxy: _proxyManager.Get(),
statusCodeOK: false);
if (response.response?.StatusCode == HttpStatusCode.Forbidden
&& retryOnUnauthorized
&& withAuth
&& _auth != null
&& _auth.CanUseCredentials)
{
_onLog($"UaflixAuth: отримано 403 для {url}, виконую повторну авторизацію");
string refreshedCookie = await _auth.GetCookieHeaderAsync(forceRefresh: true);
_auth.ApplyCookieHeader(requestHeaders, refreshedCookie);
response = await Http.BaseGet(requestUrl,
headers: requestHeaders,
timeoutSeconds: timeoutSeconds,
proxy: _proxyManager.Get(),
statusCodeOK: false);
}
if (response.response?.StatusCode != HttpStatusCode.OK)
{
if (response.response != null)
_onLog($"Uaflix HTTP {(int)response.response.StatusCode} для {url}");
return null;
}
return response.content;
}
bool ShouldUseAuth(string url)
{
if (_auth == null || string.IsNullOrWhiteSpace(url) || string.IsNullOrWhiteSpace(_init?.host))
return false;
try
{
Uri siteUri = new Uri(_init.host);
Uri requestUri;
if (!Uri.TryCreate(url, UriKind.Absolute, out requestUri))
requestUri = new Uri(siteUri, url.TrimStart('/'));
return string.Equals(requestUri.Host, siteUri.Host, StringComparison.OrdinalIgnoreCase);
}
catch
{
return false;
}
}
#region Методи для визначення та парсингу різних типів плеєрів
/// <summary>
@ -144,7 +237,7 @@ namespace Uaflix
new HeadersModel("Referer", _init.host)
};
string html = await Http.Get(_init.cors(pageUrl), headers: headers, proxy: _proxyManager.Get());
string html = await GetHtml(pageUrl, headers);
if (string.IsNullOrWhiteSpace(html))
return (null, null);
@ -294,7 +387,7 @@ namespace Uaflix
}
}
string html = await Http.Get(_init.cors(AshdiRequestUrl(requestUrl)), headers: headers, proxy: _proxyManager.Get());
string html = await GetHtml(AshdiRequestUrl(requestUrl), headers);
// Знайти JSON у new Playerjs({file:'...'})
var match = Regex.Match(html, @"file:'(\[.+?\])'", RegexOptions.Singleline);
@ -405,7 +498,7 @@ namespace Uaflix
try
{
string html = await Http.Get(_init.cors(iframeUrl), headers: headers, proxy: _proxyManager.Get());
string html = await GetHtml(iframeUrl, headers);
// Знайти file:"url"
var match = Regex.Match(html, @"file:\s*""([^""]+\.m3u8)""");
@ -441,7 +534,7 @@ namespace Uaflix
try
{
string requestUrl = WithAshdiMultivoice(iframeUrl);
string html = await Http.Get(_init.cors(AshdiRequestUrl(requestUrl)), headers: headers, proxy: _proxyManager.Get());
string html = await GetHtml(AshdiRequestUrl(requestUrl), headers);
if (string.IsNullOrEmpty(html))
return result;
@ -740,7 +833,7 @@ namespace Uaflix
foreach (string query in queries)
{
string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(query)}";
string searchHtml = await Http.Get(_init.cors(searchUrl), headers: headers, proxy: _proxyManager.Get());
string searchHtml = await GetHtml(searchUrl, headers);
if (string.IsNullOrWhiteSpace(searchHtml))
continue;
@ -926,7 +1019,7 @@ namespace Uaflix
new HeadersModel("Referer", _init.host)
};
string html = await Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get());
string html = await GetHtml(url, headers);
if (!string.IsNullOrWhiteSpace(html))
{
var doc = new HtmlDocument();
@ -1152,7 +1245,7 @@ namespace Uaflix
try
{
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) };
var filmHtml = await Http.Get(_init.cors(filmUrl), headers: headers, proxy: _proxyManager.Get());
var filmHtml = await GetHtml(filmUrl, headers);
var doc = new HtmlDocument();
doc.LoadHtml(filmHtml);
@ -1227,7 +1320,7 @@ namespace Uaflix
try
{
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) };
var filmHtml = await Http.Get(_init.cors(filmUrl), headers: headers, proxy: _proxyManager.Get());
var filmHtml = await GetHtml(filmUrl, headers);
var filmDoc = new HtmlDocument();
filmDoc.LoadHtml(filmHtml);
@ -1265,7 +1358,7 @@ namespace Uaflix
if (safeSeasonUrls.Count == 0)
return null;
var seasonTasks = safeSeasonUrls.Select(url => Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get()));
var seasonTasks = safeSeasonUrls.Select(url => GetHtml(url, headers));
var seasonPagesHtml = await Task.WhenAll(seasonTasks);
foreach (var html in seasonPagesHtml)
@ -1326,7 +1419,7 @@ namespace Uaflix
var result = new Uaflix.Models.PlayResult() { streams = new List<PlayStream>() };
try
{
string html = await Http.Get(_init.cors(url), headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get());
string html = await GetHtml(url, new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) });
var doc = new HtmlDocument();
doc.LoadHtml(html);
@ -1429,7 +1522,7 @@ namespace Uaflix
async Task<List<PlayStream>> ParseAllZetvideoSources(string iframeUrl)
{
var result = new List<PlayStream>();
var html = await Http.Get(_init.cors(iframeUrl), headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://zetvideo.net/") }, proxy: _proxyManager.Get());
var html = await GetHtml(iframeUrl, new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://zetvideo.net/") });
if (string.IsNullOrEmpty(html)) return result;
var doc = new HtmlDocument();
@ -1473,7 +1566,7 @@ namespace Uaflix
async Task<List<PlayStream>> ParseAllAshdiSources(string iframeUrl)
{
var result = new List<PlayStream>();
var html = await Http.Get(_init.cors(AshdiRequestUrl(iframeUrl)), headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }, proxy: _proxyManager.Get());
var html = await GetHtml(AshdiRequestUrl(iframeUrl), new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") });
if (string.IsNullOrEmpty(html)) return result;
var doc = new HtmlDocument();
@ -1500,7 +1593,7 @@ namespace Uaflix
async Task<SubtitleTpl?> GetAshdiSubtitles(string id)
{
string url = $"https://ashdi.vip/vod/{id}";
var html = await Http.Get(_init.cors(AshdiRequestUrl(url)), headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }, proxy: _proxyManager.Get());
var html = await GetHtml(AshdiRequestUrl(url), new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") });
string subtitle = new Regex("subtitle(\")?:\"([^\"]+)\"").Match(html).Groups[2].Value;
if (!string.IsNullOrEmpty(subtitle))
{