diff --git a/README.md b/README.md index 10b23c4..f2321d9 100644 --- a/README.md +++ b/README.md @@ -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, diff --git a/Uaflix/Controller.cs b/Uaflix/Controller.cs index 3660df0..c0c2776 100644 --- a/Uaflix/Controller.cs +++ b/Uaflix/Controller.cs @@ -18,7 +18,7 @@ using Uaflix.Models; namespace Uaflix.Controllers { - public class Controller : BaseOnlineController + public class Controller : BaseOnlineController { 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() { 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("=== RETURN: checksearch OnError ==="); - return OnError("uaflix", proxyManager); - } + + 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); } diff --git a/Uaflix/ModInit.cs b/Uaflix/ModInit.cs index b934bc3..ac89304 100644 --- a/Uaflix/ModInit.cs +++ b/Uaflix/ModInit.cs @@ -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; } /// - /// модуль загружен + /// Модуль завантажено. /// 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(); + UaFlix = conf.ToObject(); + if (hasApn) ApnHelper.ApplyInitConf(apnEnabled, apnHost, UaFlix); + ApnHostProvided = hasApn && apnEnabled && !string.IsNullOrWhiteSpace(apnHost); if (hasApn && apnEnabled) { @@ -77,8 +72,8 @@ namespace Uaflix UaFlix.apnstream = false; 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 @@ -201,4 +197,4 @@ namespace Uaflix } public record ConnectResponse(bool IsUpdateUnavailable, bool IsNoiseEnabled); -} \ No newline at end of file +} diff --git a/Uaflix/Models/UaflixSettings.cs b/Uaflix/Models/UaflixSettings.cs new file mode 100644 index 0000000..cd518d1 --- /dev/null +++ b/Uaflix/Models/UaflixSettings.cs @@ -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(); + } + } +} diff --git a/Uaflix/UaflixAuth.cs b/Uaflix/UaflixAuth.cs new file mode 100644 index 0000000..e1c879a --- /dev/null +++ b/Uaflix/UaflixAuth.cs @@ -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 CookieContainers = new(); + private static readonly ConcurrentDictionary CookieHeaders = new(); + + private readonly UaflixSettings _init; + private readonly IMemoryCache _memoryCache; + private readonly Action _onLog; + private readonly ProxyManager _proxyManager; + + public UaflixAuth(UaflixSettings init, IMemoryCache memoryCache, Action 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 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 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 + { + 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 + { + ["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 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() + .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(); + var map = new Dictionary(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}/"; + } + } +} diff --git a/Uaflix/UaflixInvoke.cs b/Uaflix/UaflixInvoke.cs index c162c9e..5ca6303 100644 --- a/Uaflix/UaflixInvoke.cs +++ b/Uaflix/UaflixInvoke.cs @@ -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 _onLog; - private ProxyManager _proxyManager; + private readonly UaflixSettings _init; + private readonly IHybridCache _hybridCache; + private readonly Action _onLog; + private readonly ProxyManager _proxyManager; + private readonly UaflixAuth _auth; - public UaflixInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager) + public UaflixInvoke(UaflixSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager, UaflixAuth auth) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; + _auth = auth; } string AshdiRequestUrl(string url) @@ -46,6 +48,97 @@ namespace Uaflix return ApnHelper.WrapUrl(_init, url); } + + public async Task 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() + { + 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 GetHtml(string url, List 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(headers) : new List(); + + 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 Методи для визначення та парсингу різних типів плеєрів @@ -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() { 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() { 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() }; try { - string html = await Http.Get(_init.cors(url), headers: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get()); + string html = await GetHtml(url, new List() { 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> ParseAllZetvideoSources(string iframeUrl) { var result = new List(); - var html = await Http.Get(_init.cors(iframeUrl), headers: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://zetvideo.net/") }, proxy: _proxyManager.Get()); + var html = await GetHtml(iframeUrl, new List() { 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> ParseAllAshdiSources(string iframeUrl) { var result = new List(); - var html = await Http.Get(_init.cors(AshdiRequestUrl(iframeUrl)), headers: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }, proxy: _proxyManager.Get()); + var html = await GetHtml(AshdiRequestUrl(iframeUrl), new List() { 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 GetAshdiSubtitles(string id) { string url = $"https://ashdi.vip/vod/{id}"; - var html = await Http.Get(_init.cors(AshdiRequestUrl(url)), headers: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }, proxy: _proxyManager.Get()); + var html = await GetHtml(AshdiRequestUrl(url), new List() { 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)) {