using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using Newtonsoft.Json; using Shared.Engine; using Shared.Models.Online.Settings; using Shared.Models; using UaTUT.Models; namespace UaTUT { public class UaTUTInvoke { private static readonly HashSet NotAllowedHosts = new HashSet( new[] { "c3ZpdGFubW92aWU=", "cG9ydGFsLXR2", "bGFtcGE=", } .Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))), StringComparer.OrdinalIgnoreCase ); private OnlinesSettings _init; private HybridCache _hybridCache; private Action _onLog; private ProxyManager _proxyManager; public UaTUTInvoke(OnlinesSettings init, HybridCache hybridCache, Action onLog, ProxyManager proxyManager) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; } public async Task> Search(string query, string imdbId = null) { try { string searchUrl = $"{_init.apihost}/search.php"; // Поступовий пошук: спочатку по imdbId, потім по назві if (!string.IsNullOrEmpty(imdbId)) { var imdbResults = await PerformSearch(searchUrl, imdbId); if (imdbResults?.Any() == true) return imdbResults; } // Пошук по назві if (!string.IsNullOrEmpty(query)) { var titleResults = await PerformSearch(searchUrl, query); return titleResults ?? new List(); } return new List(); } catch (Exception ex) { _onLog($"UaTUT Search error: {ex.Message}"); return new List(); } } private async Task> PerformSearch(string searchUrl, string query) { string url = $"{searchUrl}?q={HttpUtility.UrlEncode(query)}"; _onLog($"UaTUT searching: {url}"); if (IsNotAllowedHost(url)) return null; var headers = new List() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") }; var response = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); if (string.IsNullOrEmpty(response)) return null; try { var results = JsonConvert.DeserializeObject>(response); _onLog($"UaTUT found {results?.Count ?? 0} results for query: {query}"); return results; } catch (Exception ex) { _onLog($"UaTUT parse error: {ex.Message}"); return null; } } public async Task GetMoviePageContent(string movieId) { try { string url = $"{_init.apihost}/{movieId}"; _onLog($"UaTUT getting movie page: {url}"); if (IsNotAllowedHost(url)) return null; var headers = new List() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") }; var response = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); return response; } catch (Exception ex) { _onLog($"UaTUT GetMoviePageContent error: {ex.Message}"); return null; } } public async Task GetPlayerUrl(string moviePageContent) { try { // Шукаємо iframe з id="vip-player" та class="tab-content" var match = Regex.Match(moviePageContent, @"]*id=[""']vip-player[""'][^>]*src=[""']([^""']+)[""']", RegexOptions.IgnoreCase); if (match.Success) { string playerUrl = match.Groups[1].Value; _onLog($"UaTUT found player URL: {playerUrl}"); return playerUrl; } _onLog("UaTUT: vip-player iframe not found"); return null; } catch (Exception ex) { _onLog($"UaTUT GetPlayerUrl error: {ex.Message}"); return null; } } public async Task GetPlayerData(string playerUrl) { try { _onLog($"UaTUT getting player data from: {playerUrl}"); if (IsNotAllowedHost(playerUrl)) return null; var headers = new List() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") }; var response = await Http.Get(playerUrl, headers: headers, proxy: _proxyManager.Get()); if (string.IsNullOrEmpty(response)) return null; return ParsePlayerData(response); } catch (Exception ex) { _onLog($"UaTUT GetPlayerData error: {ex.Message}"); return null; } } private static bool IsNotAllowedHost(string url) { if (string.IsNullOrEmpty(url)) return false; if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)) return false; return NotAllowedHosts.Contains(uri.Host); } private PlayerData ParsePlayerData(string playerHtml) { try { var playerData = new PlayerData(); // Для фільмів шукаємо прямий file var fileMatch = Regex.Match(playerHtml, @"file:'([^']+)'", RegexOptions.IgnoreCase); if (fileMatch.Success && !fileMatch.Groups[1].Value.StartsWith("[")) { playerData.File = fileMatch.Groups[1].Value; _onLog($"UaTUT found direct file: {playerData.File}"); // Шукаємо poster var posterMatch = Regex.Match(playerHtml, @"poster:[""']([^""']+)[""']", RegexOptions.IgnoreCase); if (posterMatch.Success) playerData.Poster = posterMatch.Groups[1].Value; return playerData; } // Для серіалів шукаємо JSON структуру з сезонами та озвучками var jsonMatch = Regex.Match(playerHtml, @"file:'(\[.*?\])'", RegexOptions.Singleline); if (jsonMatch.Success) { string jsonData = jsonMatch.Groups[1].Value; _onLog($"UaTUT found JSON data for series"); playerData.Voices = ParseVoicesJson(jsonData); return playerData; } _onLog("UaTUT: No player data found"); return null; } catch (Exception ex) { _onLog($"UaTUT ParsePlayerData error: {ex.Message}"); return null; } } private List ParseVoicesJson(string jsonData) { try { // Декодуємо JSON структуру озвучок dynamic voicesData = JsonConvert.DeserializeObject(jsonData); var voices = new List(); if (voicesData != null) { foreach (var voiceGroup in voicesData) { var voice = new Voice { Name = voiceGroup.title?.ToString(), Seasons = new List() }; if (voiceGroup.folder != null) { foreach (var seasonData in voiceGroup.folder) { var season = new Season { Title = seasonData.title?.ToString(), Episodes = new List() }; if (seasonData.folder != null) { foreach (var episodeData in seasonData.folder) { var episode = new Episode { Title = episodeData.title?.ToString(), File = episodeData.file?.ToString(), Id = episodeData.id?.ToString(), Poster = episodeData.poster?.ToString(), Subtitle = episodeData.subtitle?.ToString() }; season.Episodes.Add(episode); } } voice.Seasons.Add(season); } } voices.Add(voice); } } _onLog($"UaTUT parsed {voices.Count} voices"); return voices; } catch (Exception ex) { _onLog($"UaTUT ParseVoicesJson error: {ex.Message}"); return new List(); } } } }