using Shared.Engine.RxEnumerate; using Shared.Models; using Shared.Models.Base; using Shared.Models.Online; using Shared.Models.Online.Rezka; using Shared.Models.Online.Settings; using Shared.Models.Templates; using System.Collections.Concurrent; using System.Text; using System.Text.RegularExpressions; using System.Web; namespace Shared.Engine.Online { public class RezkaInvoke { #region RezkaInvoke RezkaSettings init; string host, scheme, route; string apihost; bool usehls, userprem, usereserve; HttpHydra httpHydra; List defaultHeaders; Func onstreamfile; Action requesterror; bool safety = false; public string requestlog = string.Empty; static readonly ConcurrentDictionary basereferer = new(); public RezkaInvoke(string host, string route, RezkaSettings init, bool safety, List defaultHeaders, HttpHydra httpHydra, Func onstreamfile, Action requesterror = null) { this.host = host != null ? $"{host}/" : null; this.route = route; this.init = init; this.safety = safety; apihost = init.corsHost(); scheme = init.scheme; this.httpHydra = httpHydra; this.defaultHeaders = defaultHeaders; this.onstreamfile = onstreamfile; usehls = init.hls; usereserve = init.reserve; userprem = init.premium; this.requesterror = requesterror; if (apihost.Contains("=")) { char[] buffer = apihost.ToCharArray(); for (int i = 0; i < buffer.Length; i++) { char letter = buffer[i]; letter = (char)(letter - 3); buffer[i] = letter; } apihost = new string(buffer); } } #endregion #region Search async public Task Search(string title, string original_title, int clarification, int year) { var result = new SearchModel(); string reservedlink = null; var base_headers = HeadersModel.Init(init.headers, ("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"), ("cache-control", "no-cache"), ("dnt", "1"), ("pragma", "no-cache"), ("sec-fetch-dest", "document"), ("sec-fetch-mode", "navigate"), ("sec-fetch-site", "same-origin"), ("sec-fetch-user", "?1"), ("upgrade-insecure-requests", "1"), ("referer", $"{apihost}/") ); var newheaders = init.premium ? defaultHeaders : HeadersModel.Join(base_headers, defaultHeaders); result.search_uri = $"{apihost}/search/?do=search&subaction=search&q={HttpUtility.UrlEncode(clarification == 1 ? title : (original_title ?? title))}"; await httpHydra.GetSpan(result.search_uri, statusCodeOK: false, safety: safety, newheaders: newheaders, spanAction: search => { if (search.Contains("class=\"error-code\"", StringComparison.OrdinalIgnoreCase) && search.Contains("ошибка доступа", StringComparison.OrdinalIgnoreCase)) { if (search.Contains("(105)", StringComparison.Ordinal) || search.Contains(">105<", StringComparison.Ordinal) || search.Contains("(403)", StringComparison.Ordinal) || search.Contains(">403<", StringComparison.Ordinal)) { result = new SearchModel() { IsEmpty = true, content = "Ошибка доступа (105)
IP-адрес заблокирован

" }; return; } if (search.Contains("(101)", StringComparison.Ordinal) || search.Contains(">101<", StringComparison.Ordinal)) { result = new SearchModel() { IsEmpty = true, content = "Ошибка доступа (101)
Аккаунт заблокирован

" }; return; } var accessError = Rx.Groups(search, "Ошибка доступа[ \t]+\\(([0-9]+)\\)", RegexOptions.IgnoreCase); result = new SearchModel() { IsEmpty = true, content = $"Ошибка доступа ({accessError[1].Value})" }; return; } string stitle = StringConvert.SearchName(title); string sorigtitle = StringConvert.SearchName(original_title); var rx = Rx.Split("\"b-content__inline_item\"", search, 1); if (rx.Count == 0) { result.IsError = true; return; } foreach (var row in rx.Rows()) { var g = row.Groups("href=\"https?://[^/]+/([^\"]+)\">([^<]+) ?
([0-9]{4})"); if (string.IsNullOrEmpty(g[1].Value)) continue; string name = g[2].Value.Trim(); if (string.IsNullOrEmpty(name)) continue; if (result.similar == null) result.similar = new List(rx.Count); string img = row.Match(" 0 && g[3].Value == year.ToString()) result.href = reservedlink; } } if (string.IsNullOrEmpty(result.href)) { if (string.IsNullOrEmpty(reservedlink)) { if (result.similar.Count > 0) return; if (search.Contains("Результаты поиска", StringComparison.Ordinal)) { result = new SearchModel() { IsEmpty = true }; return; } result.IsError = true; return; } result.href = reservedlink; } }); if (result.IsError) requesterror?.Invoke(); return result; } #endregion #region Embed async public Task Embed(string href, string search_uri) { if (!href.StartsWith("http")) href = $"{apihost}/{href}"; var result = new EmbedModel(); var base_headers = HeadersModel.Init(init.headers, ("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"), ("cache-control", "no-cache"), ("dnt", "1"), ("pragma", "no-cache"), ("sec-fetch-dest", "document"), ("sec-fetch-mode", "navigate"), ("sec-fetch-site", "same-origin"), ("sec-fetch-user", "?1"), ("upgrade-insecure-requests", "1") ); if (!string.IsNullOrEmpty(search_uri)) base_headers.Add(new HeadersModel("referer", search_uri)); var newheaders = init.premium ? defaultHeaders : HeadersModel.Join(base_headers, defaultHeaders); result.id = Regex.Match(href, "/([0-9]+)-[^/]+\\.html").Groups[1].Value; if (long.TryParse(result.id, out long id) && id > 0) basereferer.TryAdd(id, href); bool IsTrailer = false; await httpHydra.GetSpan(href, safety: safety, newheaders: newheaders, spanAction: html => { IsTrailer = html.Contains("Ожидаем фильм в хорошем качестве", StringComparison.OrdinalIgnoreCase); if (!html.Contains("data-season_id=", StringComparison.Ordinal)) { var rx = Rx.Split("ctrl_token_id", html); if (rx.Count > 0) { var row = Rx.Split("translators-list", rx[0].Span); if (row.Count > 1) result.content = row[1].ToString(); // фильм } } else { string trs = Rx.Match(html, "\\.initCDNSeriesEvents\\([0-9]+, ([0-9]+),"); if (string.IsNullOrEmpty(trs)) return; result.trs = trs; var rx = Rx.Split("user-network-issues", html); if (rx.Count > 0) { var row = Rx.Split("b-post__lastepisodeout", rx[0].Span); if (row.Count > 1) result.content = row[1].ToString(); // сериал else if (!IsTrailer) result.content = rx[0].Span.ToString(); // что то пошло не так } } }); if (string.IsNullOrEmpty(result.content)) { if (IsTrailer) return new EmbedModel() { IsEmpty = true, content = "Ожидаем фильм в хорошем качестве..." }; requesterror?.Invoke(); return null; } return result; } #endregion #region EmbedID //async public Task EmbedID(long kinopoisk_id, string imdb_id) //{ // string search = await onpost($"{apihost}/engine/ajax/search.php", "q=%2B" + (!string.IsNullOrEmpty(imdb_id) ? imdb_id : kinopoisk_id.ToString()), null); // if (search == null) // { // requesterror?.Invoke(); // return null; // } // string link = null; // var result = new EmbedModel(); // var rx = Rx.Split("
  • ", search, 1); // foreach (var row in rx.Rows()) // { // string href = row.Match("href=\"(https?://[^\"]+)\""); // string name = row.Match("([^<]+)"); // string year = row.Match(", ([0-9]{4})(\\)| -)"); // if (string.IsNullOrEmpty(href) || string.IsNullOrEmpty(name)) // continue; // if (result.similar == null) // result.similar = new List(rx.Count); // result.similar.Add(new SimilarModel(name, year, href, null)); // link = href; // } // if (result?.similar != null && result.similar.Count > 1) // return result; // if (string.IsNullOrEmpty(link)) // { // if (search.Contains("b-search__section_title")) // return new EmbedModel() { IsEmpty = true }; // return null; // } // result!.id = Regex.Match(link, "/([0-9]+)-[^/]+\\.html").Groups[1].Value; // result.content = await onget(link, null); // if (result.content == null || string.IsNullOrEmpty(result.id)) // { // if (result.content == null) // requesterror?.Invoke(); // return null; // } // return result; //} #endregion #region Tpl public ITplResult Tpl(EmbedModel result, string args, string title, string original_title, int s, string href, bool showstream, bool rjson = false) { if (result == null || result.IsEmpty || result.content == null) return default; if (!string.IsNullOrEmpty(args)) args = $"&{args.Remove(0, 1)}"; string enc_title = HttpUtility.UrlEncode(title); string enc_original_title = HttpUtility.UrlEncode(original_title); string enc_href = HttpUtility.UrlEncode(href); if (!result.content.Contains("data-season_id=")) { #region Фильм var match = new Regex("<[^>]+ data-translator_id=\"([0-9]+)\"([^>]+)?>(?[^<]+)([^\"]+)\" [^>]+/>)?").Match(result.content); var mtpl = new MovieTpl(title, original_title, match.Length); if (match.Success) { while (match.Success) { if (!string.IsNullOrEmpty(match.Groups[1].Value) && !string.IsNullOrEmpty(match.Groups["voice"].Value)) { if (!userprem && match.Groups[0].Value.Contains("prem_translator")) { match = match.NextMatch(); continue; } string favs = Regex.Match(result.content, "id=\"ctrl_favs\" value=\"([^\"]+)\"").Groups[1].Value; string link = host + $"{route}/movie?title={enc_title}&original_title={enc_original_title}&id={result.id}&t={match.Groups[1].Value}&favs={favs}"; string voice_href = Regex.Match(match.Groups[0].Value, "href=\"(https?://[^/]+)?/([^\"]+)\"").Groups[2].Value; if (!string.IsNullOrEmpty(voice_href)) link += $"&voice={HttpUtility.UrlEncode(voice_href)}"; #region voice string voice = match.Groups["voice"].Value.Trim(); if (!string.IsNullOrEmpty(match.Groups["imgname"].Value) && !voice.ToLower().Contains(match.Groups["imgname"].Value.ToLowerAndTrim())) voice += $" ({match.Groups["imgname"].Value.Trim()})"; if (voice == "-" || string.IsNullOrEmpty(voice)) voice = "Оригинал"; #endregion if (match.Groups[2].Value.Contains("data-director=\"1\"")) link += "&director=1"; string stream = null; if (showstream) { stream = usehls ? $"{link.Replace("/movie", "/movie.m3u8")}&play=true" : $"{link}&play=true"; stream += args; } mtpl.Append(voice, link, "call", stream); } match = match.NextMatch(); } } else { var links = getStreamLink(Regex.Match(result.content, "\"id\":\"cdnplayer\",\"streams\":\"([^\"]+)\"").Groups[1].Value.Replace("\\", "")); if (links.Count == 0) return default; var streamquality = new StreamQualityTpl(links.Select(l => (onstreamfile(l.stream_url!), l.title!))); var first = streamquality.Firts(); mtpl.Append(first.quality, onstreamfile(first.link), streamquality: streamquality); } return mtpl; #endregion } else { #region Перевод var vtpl = new VoiceTpl(); if (result.content.Contains("data-translator_id=")) { var match = new Regex("<[a-z]+ [^>]+ data-translator_id=\"(?[0-9]+)\"([^>]+)?>(?[^<]+)([^\"]+)\" [^>]+/>)?").Match(result.content); while (match.Success) { if (!userprem && match.Groups[0].Value.Contains("prem_translator")) { match = match.NextMatch(); continue; } string name = match.Groups["name"].Value.Trim(); if (!string.IsNullOrEmpty(match.Groups["imgname"].Value) && !name.ToLower().Contains(match.Groups["imgname"].Value.ToLowerAndTrim())) name += $" ({match.Groups["imgname"].Value})"; string link = host + $"{route}/serial?rjson={rjson}&title={enc_title}&original_title={enc_original_title}&href={enc_href}&id={result.id}&t={match.Groups["translator"].Value}"; string voice_href = Regex.Match(match.Groups[0].Value, "href=\"(https?://[^/]+)?/([^\"]+)\"").Groups[2].Value; if (!string.IsNullOrEmpty(voice_href) && init.ajax != null && init.ajax.Value == false) { string voice = HttpUtility.UrlEncode(voice_href); link = host + $"{route}?rjson={rjson}&title={enc_title}&original_title={enc_original_title}&href={voice}&id={result.id}&t={match.Groups["translator"].Value}"; } vtpl.Append(name, match.Groups["translator"].Value == result.trs, link); match = match.NextMatch(); } } #endregion #region Сериал var tpl = new SeasonTpl(vtpl); var etpl = new EpisodeTpl(vtpl); HashSet eshash = new HashSet(); string sArhc = s.ToString(); var m = Regex.Match(result.content, "data-cdn_url=\"(?[^\"]+)\" [^>]+ data-season_id=\"(?[0-9]+)\" data-episode_id=\"(?[0-9]+)\"([^>]+)?>(?[^>]+)"); while (m.Success) { if (s == -1) { #region Сезоны string sname = $"{m.Groups["season"].Value} сезон"; if (!string.IsNullOrEmpty(m.Groups["season"].Value) && !eshash.Contains(sname)) { eshash.Add(sname); string link = host + $"{route}?rjson={rjson}&title={enc_title}&original_title={enc_original_title}&href={enc_href}&t={result.trs}&s={m.Groups["season"].Value}"; tpl.Append(sname, link, m.Groups["season"].Value); } #endregion } else { #region Серии if (m.Groups["season"].Value == sArhc && !eshash.Contains(m.Groups["name"].Value)) { eshash.Add(m.Groups["name"].Value); string link = host + $"{route}/movie?title={enc_title}&original_title={enc_original_title}&id={result.id}&t={result.trs}&s={s}&e={m.Groups["episode"].Value}"; string voice_href = Regex.Match(m.Groups[0].Value, "href=\"(https?://[^/]+)?/([^\"]+)\"").Groups[2].Value; if (!string.IsNullOrEmpty(voice_href)) link += $"&voice={HttpUtility.UrlEncode(voice_href)}"; string stream = null; if (showstream) { stream = usehls ? $"{link.Replace("/movie", "/movie.m3u8")}&play=true" : $"{link}&play=true"; stream += args; } etpl.Append(m.Groups["name"].Value, title ?? original_title, sArhc, m.Groups["episode"].Value, link, "call", streamlink: stream); } #endregion } m = m.NextMatch(); } if (s == -1) return tpl; return etpl; #endregion } } #endregion #region Serial async public Task SerialEmbed(long id, int t) { var base_headers = HeadersModel.Init(init.headers, ("accept", "application/json, text/javascript, */*; q=0.01"), ("cache-control", "no-cache"), ("dnt", "1"), ("origin", apihost), ("pragma", "no-cache"), ("sec-fetch-dest", "empty"), ("sec-fetch-mode", "cors"), ("sec-fetch-site", "same-origin"), ("x-requested-with", "XMLHttpRequest") ); if (basereferer.TryGetValue(id, out string referer) && !string.IsNullOrEmpty(referer)) base_headers.Add(new HeadersModel("referer", referer)); var newheaders = init.premium ? defaultHeaders : HeadersModel.Join(base_headers, defaultHeaders); string uri = $"{apihost}/ajax/get_cdn_series/?t={((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds()}{Random.Shared.Next(101, 999)}"; string data = $"id={id}&translator_id={t}&action=get_episodes"; var root = await httpHydra.Post(uri, data, safety: safety, newheaders: newheaders); if (root == null) { requesterror?.Invoke(); return null; } string episodes = root.episodes; if (string.IsNullOrWhiteSpace(episodes) || episodes.Contains("false", StringComparison.OrdinalIgnoreCase)) return null; return root; } public ITplResult Serial(Episodes root, EmbedModel result, string args, string title, string original_title, string href, long id, int t, int s, bool showstream, bool rjson = false) { if (root == null || result == null) return default; if (!string.IsNullOrEmpty(args)) args = $"&{args.Remove(0, 1)}"; string enc_title = HttpUtility.UrlEncode(title); string enc_original_title = HttpUtility.UrlEncode(original_title); string enc_href = HttpUtility.UrlEncode(href); #region Перевод var vtpl = new VoiceTpl(); { if (string.IsNullOrWhiteSpace(href)) return default; if (result?.content != null) { if (result.content.Contains("data-translator_id=")) { var match = new Regex("<[a-z]+ [^>]+ data-translator_id=\"(?[0-9]+)\"([^>]+)?>(?[^<]+)([^\"]+)\" [^>]+/>)?").Match(result.content); while (match.Success) { if (!userprem && match.Groups[0].Value.Contains("prem_translator")) { match = match.NextMatch(); continue; } string name = match.Groups["name"].Value.Trim() + (string.IsNullOrWhiteSpace(match.Groups["imgname"].Value) ? "" : $" ({match.Groups["imgname"].Value})"); string link = host + $"{route}/serial?rjson={rjson}&title={enc_title}&original_title={enc_original_title}&href={enc_href}&id={id}&t={match.Groups["translator"].Value}"; vtpl.Append(name, match.Groups["translator"].Value == t.ToString(), link); match = match.NextMatch(); } } } } #endregion if (s == -1) { #region Сезоны var tpl = new SeasonTpl(vtpl, root.seasons.Length); var match = new Regex("data-tab_id=\"(?[0-9]+)\"([^>]+)?>(?[^<]+)").Match(root.seasons); while (match.Success) { string link = host + $"{route}/serial?rjson={rjson}&title={enc_title}&original_title={enc_original_title}&href={enc_href}&id={id}&t={t}&s={match.Groups["season"].Value}"; tpl.Append($"{match.Groups["season"].Value} сезон", link, match.Groups["season"].Value); match = match.NextMatch(); } return tpl; #endregion } else { #region Серии var etpl = new EpisodeTpl(vtpl); var m = new Regex($"data-season_id=\"{s}\" data-episode_id=\"(?[0-9]+)\"([^>]+)?>(?[^<]+)
  • ").Match(root.episodes); while (m.Success) { if (!string.IsNullOrEmpty(m.Groups["episode"].Value) && !string.IsNullOrEmpty(m.Groups["name"].Value)) { string link = host + $"{route}/movie?title={enc_title}&original_title={enc_original_title}&id={id}&t={t}&s={s}&e={m.Groups["episode"].Value}"; string voice_href = Regex.Match(m.Groups[0].Value, "href=\"(https?://[^/]+)?/([^\"]+)\"").Groups[2].Value; if (!string.IsNullOrEmpty(voice_href)) link += $"&voice={HttpUtility.UrlEncode(voice_href)}"; string stream = usehls ? $"{link.Replace("/movie", "/movie.m3u8")}&play=true" : $"{link}&play=true"; etpl.Append(m.Groups["name"].Value, title ?? original_title, s.ToString(), m.Groups["episode"].Value, link, "call", streamlink: (showstream ? $"{stream}{args}" : null)); } m = m.NextMatch(); } return etpl; #endregion } } #endregion #region Movie async public Task Movie(long id, int t, int director, int s, int e, string favs) { string data = null; string uri = $"{apihost}/ajax/get_cdn_series/?t={((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds()}{Random.Shared.Next(101, 999)}"; if (s == -1) { data = $"id={id}&translator_id={t}&is_camrip=0&is_ads=0&is_director={director}&favs={favs}&action=get_movie"; } else { data = $"id={id}&translator_id={t}&season={s}&episode={e}&favs={favs}&action=get_stream"; } var base_headers = HeadersModel.Init(init.headers, ("accept", "application/json, text/javascript, */*; q=0.01"), ("cache-control", "no-cache"), ("dnt", "1"), ("origin", apihost), ("pragma", "no-cache"), ("sec-fetch-dest", "empty"), ("sec-fetch-mode", "cors"), ("sec-fetch-site", "same-origin"), ("x-requested-with", "XMLHttpRequest") ); if (basereferer.TryGetValue(id, out string referer) && !string.IsNullOrEmpty(referer)) base_headers.Add(new HeadersModel("referer", referer)); var newheaders = init.premium ? defaultHeaders : HeadersModel.Join(base_headers, defaultHeaders); var root = await httpHydra.Post>(uri, data, safety: safety, newheaders: newheaders); if (root == null) { requesterror?.Invoke(); return null; } string url = root.ContainsKey("url") ? root["url"]?.ToString() : null; if (string.IsNullOrEmpty(url) || url.Contains("false", StringComparison.OrdinalIgnoreCase)) { requesterror?.Invoke(); return null; } var links = getStreamLink(url); if (links.Count == 0) return null; string subtitlehtml = null; try { subtitlehtml = root?["subtitle"]?.ToString(); } catch { } return new MovieModel() { links = links, subtitlehtml = subtitlehtml }; } async public Task Movie(string href) { var base_headers = HeadersModel.Init(init.headers, ("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"), ("cache-control", "no-cache"), ("dnt", "1"), ("pragma", "no-cache"), ("sec-fetch-dest", "document"), ("sec-fetch-mode", "navigate"), ("sec-fetch-site", "same-origin"), ("sec-fetch-user", "?1"), ("upgrade-insecure-requests", "1") ); var newheaders = init.premium ? defaultHeaders : HeadersModel.Join(base_headers, defaultHeaders); List links = null; string subtitlehtml = null; await httpHydra.GetSpan($"{apihost}/{href}", safety: safety, newheaders: newheaders, spanAction: html => { string url = Rx.Match(html, "\"streams\"\\s*:\\s*\"(.*?)\"\\s*,"); if (string.IsNullOrEmpty(url) || url.Contains("false", StringComparison.OrdinalIgnoreCase)) return; links = getStreamLink(url.Replace("\\", "")); if (links.Count > 0) subtitlehtml = Rx.Match(html, "\"subtitle\":\"([^\"]+)\""); }); if (links == null || links.Count == 0) { requesterror?.Invoke(); return null; } return new MovieModel() { links = links, subtitlehtml = subtitlehtml }; } public string Movie(MovieModel md, string title, string original_title, bool play, VastConf vast = null) { if (play) return onstreamfile(md.links[0].stream_url!); #region subtitles var subtitles = new SubtitleTpl(); try { if (!string.IsNullOrWhiteSpace(md.subtitlehtml)) { var m = Regex.Match(md.subtitlehtml, "\\[([^\\]]+)\\](https?://[^\n\r,']+\\.vtt)"); while (m.Success) { if (!string.IsNullOrEmpty(m.Groups[1].Value) && !string.IsNullOrEmpty(m.Groups[2].Value)) subtitles.Append(m.Groups[1].Value, onstreamfile(m.Groups[2].Value)); m = m.NextMatch(); } } } catch { } #endregion var streamquality = new StreamQualityTpl(); foreach (var l in md.links) streamquality.Append(onstreamfile(l.stream_url!), l.title); return VideoTpl.ToJson("play", onstreamfile(md.links[0].stream_url!), (title ?? original_title ?? "auto"), streamquality: streamquality, subtitles: subtitles, vast: vast, hls_manifest_timeout: (int)TimeSpan.FromSeconds(20).TotalMilliseconds ); } #endregion #region decodeBase64 static string[] trashListBase = ["JCQhIUAkJEBeIUAjJCRA", "QEBAQEAhIyMhXl5e", "IyMjI14hISMjIUBA", "Xl5eIUAjIyEhIyM=", "JCQjISFAIyFAIyM="]; static string[] trashListOld = ["QEA=", "QCM=", "QCE=", "QF4=", "QCQ=", "I0A=", "IyM=", "IyE=", "I14=", "IyQ=", "IUA=", "ISM=", "ISE=", "IV4=", "ISQ=", "XkA=", "XiM=", "XiE=", "Xl4=", "XiQ=", "JEA=", "JCM=", "JCE=", "JF4=", "JCQ=", "QEBA", "QEAj", "QEAh", "QEBe", "QEAk", "QCNA", "QCMj", "QCMh", "QCNe", "QCMk", "QCFA", "QCEj", "QCEh", "QCFe", "QCEk", "QF5A", "QF4j", "QF4h", "QF5e", "QF4k", "QCRA", "QCQj", "QCQh", "QCRe", "QCQk", "I0BA", "I0Aj", "I0Ah", "I0Be", "I0Ak", "IyNA", "IyMj", "IyMh", "IyNe", "IyMk", "IyFA", "IyEj", "IyEh", "IyFe", "IyEk", "I15A", "I14j", "I14h", "I15e", "I14k", "IyRA", "IyQj", "IyQh", "IyRe", "IyQk", "IUBA", "IUAj", "IUAh", "IUBe", "IUAk", "ISNA", "ISMj", "ISMh", "ISNe", "ISMk", "ISFA", "ISEj", "ISEh", "ISFe", "ISEk", "IV5A", "IV4j", "IV4h", "IV5e", "IV4k", "ISRA", "ISQj", "ISQh", "ISRe", "ISQk", "XkBA", "XkAj", "XkAh", "XkBe", "XkAk", "XiNA", "XiMj", "XiMh", "XiNe", "XiMk", "XiFA", "XiEj", "XiEh", "XiFe", "XiEk", "Xl5A", "Xl4j", "Xl4h", "Xl5e", "Xl4k", "XiRA", "XiQj", "XiQh", "XiRe", "XiQk", "JEBA", "JEAj", "JEAh", "JEBe", "JEAk", "JCNA", "JCMj", "JCMh", "JCNe", "JCMk", "JCFA", "JCEj", "JCEh", "JCFe", "JCEk", "JF5A", "JF4j", "JF4h", "JF5e", "JF4k", "JCRA", "JCQj", "JCQh", "JCRe", "JCQk"]; static string decodeBase64(string data) { if (data.StartsWith("#")) { try { string _data = data.Remove(0, 2); foreach (string trash in trashListBase) { if (_data.Contains($"//_//{trash}")) _data = _data.Replace($"//_//{trash}", ""); } try { return Encoding.UTF8.GetString(Convert.FromBase64String(_data)); } catch { _data = Regex.Replace(_data, "//[^/]+_//", "").Replace("//_//", ""); _data = Encoding.UTF8.GetString(Convert.FromBase64String(_data)); return _data; } } catch { string _data = data.Remove(0, 2).Replace("//_//", ""); foreach (string trash in trashListOld) { if (_data.Contains(trash)) _data = _data.Replace(trash, ""); } _data = Regex.Replace(_data, "//[^/]+_//", "").Replace("//_//", ""); _data = Encoding.UTF8.GetString(Convert.FromBase64String(_data)); return _data; } } return data; } #endregion #region getStreamLink List getStreamLink(string _data) { string data = decodeBase64(_data); var links = new List(6); #region getLink string getLink(string _q) { string qline = Regex.Match(data, $"\\[({_q}|[^\\]]+{_q}[^\\]]+)\\]([^,\\[]+)").Groups[2].Value; if (!qline.Contains(".mp4") && !qline.Contains(".m3u8")) return null; if (usereserve && qline.Contains(" or ")) { return string.Join(" or ", qline.Split(" or ").Select(i => { string l = Regex.Match(i, "(https?://[^\\[\n\r, ]+)").Groups[1].Value; if (usehls) { if (l.EndsWith(".m3u8")) return l; return l + ":hls:manifest.m3u8"; } return l.Replace(":hls:manifest.m3u8", ""); })); } else { string link = Regex.Match(qline, "(https?://[^\\[\n\r, ]+)").Groups[1].Value; if (string.IsNullOrEmpty(link)) return null; if (usehls) { if (link.EndsWith(".m3u8")) return link; return link + ":hls:manifest.m3u8"; } return link.Replace(":hls:manifest.m3u8", ""); } } #endregion #region Максимально доступное var qualities = new List { "2160p", "1440p", "1080p", "720p", "480p" }; if (userprem) qualities.InsertRange(2, new List { "1080p Ultra" }); foreach (string q in qualities) { string link = null; switch (q) { case "2160p": link = getLink("4K") ?? getLink(q); break; case "1440p": link = getLink("2K") ?? getLink(q); break; case "1080p": link = userprem ? getLink(q) : (getLink(q) ?? getLink("1080p Ultra")); break; default: link = getLink(q); break; } if (string.IsNullOrEmpty(link)) continue; if (scheme == "http") link = link.Replace("https:", "http:"); string realq = q; switch (q) { case "1080p Ultra": realq = "1080p"; break; case "1080p": realq = "720p"; break; case "720p": realq = "480p"; break; case "480p": realq = "360p"; break; } links.Add(new ApiModel() { title = realq, stream_url = link }); } #endregion return links; } #endregion #region fixcdn public static string fixcdn(string country, string uacdn, string link) { if (uacdn != null && country == "UA" && !link.Contains(".vtt")) return Regex.Replace(link, "https?://[^/]+", uacdn); return link; } #endregion #region StreamProxyHeaders public static List StreamProxyHeaders(RezkaSettings init) => HeadersModel.Init(init.headers, ("accept", "*/*"), ("cache-control", "no-cache"), ("dnt", "1"), ("origin", init.host), ("pragma", "no-cache"), ("referer", $"{init.host}/"), ("sec-fetch-dest", "empty"), ("sec-fetch-mode", "cors"), ("sec-fetch-site", "cross-site") ); #endregion } }