using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.Json; using System.Threading.Tasks; using System.Web; using Shared; using Shared.Engine; using Shared.Models; using Shared.Models.Online.Settings; using StarLight.Models; namespace StarLight { public class StarLightInvoke { private const string PlayerApi = "https://vcms-api2.starlight.digital/player-api"; private const string PlayerReferer = "https://teleportal.ua/"; private const string Language = "ua"; private static readonly HashSet NotAllowedHosts = new HashSet( new[] { "c3ZpdGFubW92aWU=", "cG9ydGFsLXR2", } .Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))), StringComparer.OrdinalIgnoreCase ); private readonly OnlinesSettings _init; private readonly HybridCache _hybridCache; private readonly Action _onLog; private readonly ProxyManager _proxyManager; public StarLightInvoke(OnlinesSettings init, HybridCache hybridCache, Action onLog, ProxyManager proxyManager) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; } public async Task> Search(string title, string original_title) { string query = !string.IsNullOrEmpty(title) ? title : original_title; if (string.IsNullOrEmpty(query)) return null; string memKey = $"StarLight:search:{query}"; if (_hybridCache.TryGetValue(memKey, out List cached)) return cached; string url = $"{_init.host}/{Language}/live-search?q={HttpUtility.UrlEncode(query)}"; if (IsNotAllowedHost(url)) return null; var headers = new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }; try { _onLog?.Invoke($"StarLight search: {url}"); string payload = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); if (string.IsNullOrEmpty(payload)) return null; var results = new List(); using var document = JsonDocument.Parse(payload); if (document.RootElement.ValueKind == JsonValueKind.Array) { foreach (var item in document.RootElement.EnumerateArray()) { string typeSlug = item.TryGetProperty("typeSlug", out var typeProp) ? typeProp.GetString() : null; string channelSlug = item.TryGetProperty("channelSlug", out var channelProp) ? channelProp.GetString() : null; string projectSlug = item.TryGetProperty("projectSlug", out var projectProp) ? projectProp.GetString() : null; if (string.IsNullOrEmpty(typeSlug) || string.IsNullOrEmpty(channelSlug) || string.IsNullOrEmpty(projectSlug)) continue; string href = $"{_init.host}/{Language}/{typeSlug}/{channelSlug}/{projectSlug}"; results.Add(new SearchResult { Title = item.TryGetProperty("title", out var titleProp) ? titleProp.GetString() : null, Type = typeSlug, Href = href, Channel = channelSlug, Project = projectSlug }); } } if (results.Count > 0) _hybridCache.Set(memKey, results, cacheTime(15, init: _init)); return results; } catch (Exception ex) { _onLog?.Invoke($"StarLight search error: {ex.Message}"); return null; } } public async Task GetProject(string href) { if (string.IsNullOrEmpty(href)) return null; string memKey = $"StarLight:project:{href}"; if (_hybridCache.TryGetValue(memKey, out ProjectInfo cached)) return cached; var headers = new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }; try { if (IsNotAllowedHost(href)) return null; _onLog?.Invoke($"StarLight project: {href}"); string payload = await Http.Get(href, headers: headers, proxy: _proxyManager.Get()); if (string.IsNullOrEmpty(payload)) return null; using var document = JsonDocument.Parse(payload); var root = document.RootElement; var project = new ProjectInfo { Title = root.TryGetProperty("title", out var titleProp) ? titleProp.GetString() : null, Description = root.TryGetProperty("description", out var descProp) ? descProp.GetString() : null, Poster = NormalizeImage(root.TryGetProperty("image", out var imageProp) ? imageProp.GetString() : null), Hash = root.TryGetProperty("hash", out var hashProp) ? hashProp.GetString() : null, Type = root.TryGetProperty("typeSlug", out var typeProp) ? typeProp.GetString() : null, Channel = root.TryGetProperty("channelTitle", out var channelProp) ? channelProp.GetString() : null }; if (root.TryGetProperty("seasons", out var seasonsListProp) && seasonsListProp.ValueKind == JsonValueKind.Array) { foreach (var seasonItem in seasonsListProp.EnumerateArray()) { string seasonTitle = seasonItem.TryGetProperty("title", out var sTitle) ? sTitle.GetString() : null; string seasonSlug = seasonItem.TryGetProperty("seasonSlug", out var sSlug) ? sSlug.GetString() : null; AddSeason(project, seasonTitle, seasonSlug); } } if (root.TryGetProperty("seasonsGallery", out var seasonsProp) && seasonsProp.ValueKind == JsonValueKind.Array) { foreach (var seasonItem in seasonsProp.EnumerateArray()) { string seasonTitle = seasonItem.TryGetProperty("title", out var sTitle) ? sTitle.GetString() : null; string seasonSlug = seasonItem.TryGetProperty("seasonSlug", out var sSlug) ? sSlug.GetString() : null; AddSeason(project, seasonTitle, seasonSlug); if (seasonItem.TryGetProperty("items", out var itemsProp) && itemsProp.ValueKind == JsonValueKind.Array) { foreach (var item in itemsProp.EnumerateArray()) { project.Episodes.Add(new EpisodeInfo { Title = item.TryGetProperty("title", out var eTitle) ? eTitle.GetString() : null, Hash = item.TryGetProperty("hash", out var eHash) ? eHash.GetString() : null, VideoSlug = item.TryGetProperty("videoSlug", out var eSlug) ? eSlug.GetString() : null, Date = item.TryGetProperty("dateOfBroadcast", out var eDate) ? eDate.GetString() : (item.TryGetProperty("timeUploadVideo", out var eDate2) ? eDate2.GetString() : null), SeasonSlug = seasonSlug }); } } } } await LoadMissingSeasonEpisodes(project, href, headers); _hybridCache.Set(memKey, project, cacheTime(10, init: _init)); return project; } catch (Exception ex) { _onLog?.Invoke($"StarLight project error: {ex.Message}"); return null; } } private async Task LoadMissingSeasonEpisodes(ProjectInfo project, string href, List headers) { if (project == null || string.IsNullOrEmpty(href)) return; var missing = project.Seasons .Where(s => !string.IsNullOrEmpty(s.Slug)) .Where(s => !project.Episodes.Any(e => e.SeasonSlug == s.Slug)) .ToList(); foreach (var seasonInfo in missing) { string seasonUrl = $"{href}/{seasonInfo.Slug}"; try { _onLog?.Invoke($"StarLight season: {seasonUrl}"); string payload = await Http.Get(seasonUrl, headers: headers, proxy: _proxyManager.Get()); if (string.IsNullOrEmpty(payload)) continue; using var document = JsonDocument.Parse(payload); var root = document.RootElement; if (root.TryGetProperty("items", out var itemsProp) && itemsProp.ValueKind == JsonValueKind.Array) { foreach (var item in itemsProp.EnumerateArray()) { string hash = item.TryGetProperty("hash", out var eHash) ? eHash.GetString() : null; if (string.IsNullOrEmpty(hash)) continue; if (project.Episodes.Any(e => e.SeasonSlug == seasonInfo.Slug && e.Hash == hash)) continue; project.Episodes.Add(new EpisodeInfo { Title = item.TryGetProperty("title", out var eTitle) ? eTitle.GetString() : null, Hash = hash, VideoSlug = item.TryGetProperty("videoSlug", out var eSlug) ? eSlug.GetString() : null, Date = item.TryGetProperty("dateOfBroadcast", out var eDate) ? eDate.GetString() : (item.TryGetProperty("timeUploadVideo", out var eDate2) ? eDate2.GetString() : null), SeasonSlug = seasonInfo.Slug }); } } } catch (Exception ex) { _onLog?.Invoke($"StarLight season error: {ex.Message}"); } } } private static void AddSeason(ProjectInfo project, string title, string slug) { if (project == null || string.IsNullOrEmpty(slug)) return; if (project.Seasons.Any(s => s.Slug == slug)) return; project.Seasons.Add(new SeasonInfo { Title = title, Slug = slug }); } public List GetEpisodes(ProjectInfo project, string seasonSlug) { if (project == null || project.Seasons.Count == 0) return new List(); if (string.IsNullOrEmpty(seasonSlug)) return project.Episodes; return project.Episodes.Where(e => e.SeasonSlug == seasonSlug).ToList(); } public async Task ResolveStream(string hash) { if (string.IsNullOrEmpty(hash)) return null; string url = $"{PlayerApi}/{hash}?referer={HttpUtility.UrlEncode(PlayerReferer)}&lang={Language}"; if (IsNotAllowedHost(url)) return null; var headers = new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", PlayerReferer) }; try { _onLog?.Invoke($"StarLight stream: {url}"); string payload = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); if (string.IsNullOrEmpty(payload)) return null; using var document = JsonDocument.Parse(payload); var root = document.RootElement; string stream = null; if (root.TryGetProperty("video", out var videoProp) && videoProp.ValueKind == JsonValueKind.Array) { var video = videoProp.EnumerateArray().FirstOrDefault(); if (video.ValueKind != JsonValueKind.Undefined) { if (video.TryGetProperty("mediaHlsNoAdv", out var hlsNoAdv)) stream = hlsNoAdv.GetString(); if (string.IsNullOrEmpty(stream) && video.TryGetProperty("mediaHls", out var hls)) stream = hls.GetString(); if (string.IsNullOrEmpty(stream) && video.TryGetProperty("media", out var mediaProp) && mediaProp.ValueKind == JsonValueKind.Array) { var media = mediaProp.EnumerateArray().FirstOrDefault(); if (media.TryGetProperty("url", out var mediaUrl)) stream = mediaUrl.GetString(); } } } if (string.IsNullOrEmpty(stream)) return null; return new StreamResult { Stream = stream, Poster = root.TryGetProperty("poster", out var posterProp) ? posterProp.GetString() : null, Name = root.TryGetProperty("name", out var nameProp) ? nameProp.GetString() : null }; } catch (Exception ex) { _onLog?.Invoke($"StarLight stream error: {ex.Message}"); return null; } } private string NormalizeImage(string path) { if (string.IsNullOrEmpty(path)) return string.Empty; if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) return IsNotAllowedHost(path) ? string.Empty : path; return IsNotAllowedHost(_init.host) ? string.Empty : $"{_init.host}{path}"; } 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); } public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) { if (init != null && init.rhub && rhub != -1) return TimeSpan.FromMinutes(rhub); int ctime = AppInit.conf.mikrotik ? mikrotik : AppInit.conf.multiaccess ? init != null && init.cache_time > 0 ? init.cache_time : multiaccess : home; if (ctime > multiaccess) ctime = multiaccess; return TimeSpan.FromMinutes(ctime); } } }