using Shared.Models.Online.Settings; using Shared.Models.Online.VideoCDN; using Shared.Models.Templates; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; using System.Web; namespace Shared.Engine.Online { public struct VideoCDNInvoke { #region VideoCDNInvoke string host, scheme; string iframeapihost; string apihost; string token; bool usehls; Func> onget; Func onstreamfile; Action requesterror; public string onstream(string stream) { if (onstreamfile == null) return stream; return onstreamfile.Invoke(stream); } public VideoCDNInvoke(OnlinesSettings init, Func> onget, Func onstreamfile, string host = null, Action requesterror = null) { this.host = host != null ? $"{host}/" : null; this.scheme = init.scheme; this.iframeapihost = init.corsHost(); this.apihost = init.cors(init.apihost); this.token = init!.token; this.onget = onget; this.onstreamfile = onstreamfile; usehls = init.hls; this.requesterror = requesterror; } #endregion #region Search public async Task Search(string title, string original_title, int serial) { if (string.IsNullOrWhiteSpace(title ?? original_title)) return null; string uri = $"{apihost}/api/short?api_token={token}&title={HttpUtility.UrlEncode(original_title ?? title)}"; string json = await onget.Invoke(uri, apihost); if (json == null) { requesterror?.Invoke(); return null; } SearchRoot root = null; try { root = JsonSerializer.Deserialize(json); if (root?.data == null || root.data.Length == 0) return null; } catch { return null; } var stpl = new SimilarTpl(root.data.Length); string enc_title = HttpUtility.UrlEncode(title); string enc_original_title = HttpUtility.UrlEncode(original_title); foreach (var item in root.data) { if (item.kp_id == 0 && string.IsNullOrEmpty(item.imdb_id)) continue; if (serial != -1) { if ((serial == 0 && item.content_type != "movie") || (serial == 1 && item.content_type == "movie")) continue; } bool isok = title != null && title.Length > 3 && item.title != null && item.title.ToLower().Contains(title.ToLower()); isok = isok ? true : original_title != null && original_title.Length > 3 && item.orig_title != null && item.orig_title.ToLower().Contains(original_title.ToLower()); if (!isok) continue; string year = item.add?.Split("-")?[0] ?? string.Empty; string name = !string.IsNullOrEmpty(item.title) && !string.IsNullOrEmpty(item.orig_title) ? $"{item.title} / {item.orig_title}" : (item.title ?? item.orig_title); string details = $"imdb: {item.imdb_id} {SimilarTpl.OnlineSplit} kinopoisk: {item.kp_id}"; stpl.Append(name, year, details, host + $"lite/vcdn?title={enc_title}&original_title={enc_original_title}&kinopoisk_id={item.kp_id}&imdb_id={item.imdb_id}"); } return stpl; } #endregion #region Embed public async Task Embed(long kinopoisk_id, string imdb_id) { string args = kinopoisk_id > 0 ? $"kp_id={kinopoisk_id}&imdb_id={imdb_id}" : $"imdb_id={imdb_id}"; string content = await onget.Invoke($"{iframeapihost}?{args}", "https://kinogo.ec/113447-venom-3-poslednij-tanec.html"); if (content == null) { requesterror?.Invoke(); return null; } var result = new EmbedModel(); result.type = Regex.Match(content, "id=\"videoType\" value=\"([^\"]+)\"").Groups[1].Value; result.voices = new Dictionary(); if (content.Contains("")) { result.voices.TryAdd("0", "По умолчанию"); var match = new Regex("").Match(Regex.Replace(content, "[\n\r\t]+", "")); while (match.Success) { string translation_id = match.Groups[1].Value; string translation = match.Groups[2].Value.Trim(); if (!string.IsNullOrEmpty(translation_id) && !string.IsNullOrEmpty(translation)) result.voices.TryAdd(translation_id, translation); match = match.NextMatch(); } } string Decode(string pass, string src) { try { int passLen = pass.Length; int srcLen = src.Length; byte[] passArr = new byte[passLen]; for (int i = 0; i < passLen; i++) { passArr[i] = (byte)pass[i]; } StringBuilder res = new StringBuilder(PoolInvk.rentChunk); for (int i = 0; i < srcLen; i += 2) { string hex = src.Substring(i, 2); int code = Convert.ToInt32(hex, 16); byte secret = (byte)(passArr[(i / 2) % passLen] % 255); res.Append((char)(code ^ secret)); } return res.ToString(); } catch { return null; } } string files = null; string client_id = Regex.Match(content, "id=\"client_id\" value=\"([^\"]+)\"").Groups[1].Value; var m = Regex.Match(content, " sentry_id.Length || sentry_id.StartsWith("{")) { m = m.NextMatch(); continue; } files = Decode(client_id, sentry_id); if (!string.IsNullOrEmpty(files)) break; m = m.NextMatch(); } if (string.IsNullOrEmpty(files)) { files = Regex.Match(content, "value='(\\{\"[0-9]+\"[^\']+)'").Groups[1].Value; if (string.IsNullOrEmpty(files)) return null; } result.quality = files.Contains("1080p") ? "1080p" : files.Contains("720p") ? "720p" : "480p"; try { if (result.type is "movie" or "anime") { result.movie = JsonSerializer.Deserialize>(files); if (result.movie == null) return null; } else { result.serial = JsonSerializer.Deserialize>>(files); if (result.serial == null) return null; #region voiceSeasons result.voiceSeasons = new Dictionary>(); foreach (var voice in result.serial.OrderByDescending(k => k.Key == "0")) { if (result.voices.TryGetValue(voice.Key, out string name) && name != null) { foreach (var season in voice.Value) { if (result.voiceSeasons.TryGetValue(voice.Key, out HashSet _s)) { _s.Add(season.id); } else { result.voiceSeasons.TryAdd(voice.Key, new HashSet() { season.id }); } } } } #endregion } } catch { return null; } return result; } #endregion #region Tpl public ITplResult Tpl(EmbedModel result, string imdb_id, long kinopoisk_id, string title, string original_title, string t, int s, bool rjson = false) { if (result == null) return default; if (result.type is "movie" or "anime") { #region Фильм if (result.movie == null || result.movie.Count == 0) return default; var mtpl = new MovieTpl(title, original_title, result.movie.Count); foreach (var voice in result.movie) { result.voices.TryGetValue(voice.Key, out string name); if (string.IsNullOrEmpty(name)) { if (result.movie.Count > 1) continue; name = "По умолчанию"; } var streamquality = new StreamQualityTpl(); foreach (Match m in Regex.Matches(voice.Value, $"\\[(1080|720|480|360)p?\\]([^\\[\\|,\n\r\t ]+\\.(mp4|m3u8))")) { string link = m.Groups[2].Value; if (string.IsNullOrEmpty(link)) continue; if (usehls && !link.Contains(".m3u")) link += ":hls:manifest.m3u8"; else if (!usehls && link.Contains(".m3u")) link = link.Replace(":hls:manifest.m3u8", ""); streamquality.Insert(onstream($"{scheme}:{link}"), $"{m.Groups[1].Value}p"); } mtpl.Append(name, streamquality.Firts().link, streamquality: streamquality); } return mtpl; #endregion } else { #region Сериал string enc_title = HttpUtility.UrlEncode(title); string enc_original_title = HttpUtility.UrlEncode(original_title); try { if (result.serial == null || result.serial.Count == 0) return default; if (s == -1) { var seasons = new HashSet(10); foreach (var voice in result.serial) { foreach (var season in voice.Value) seasons.Add(season.id); } var tpl = new SeasonTpl(result.quality, seasons.Count); foreach (int id in seasons.OrderBy(s => s)) { string link = host + $"lite/vcdn?kinopoisk_id={kinopoisk_id}&imdb_id={imdb_id}&rjson={rjson}&title={enc_title}&original_title={enc_original_title}&s={id}"; tpl.Append($"{id} сезон", link, id); } return tpl; } else { #region Перевод var vtpl = new VoiceTpl(); foreach (var voice in result.voiceSeasons) { if (!voice.Value.Contains(s)) continue; if (result.voices.TryGetValue(voice.Key, out string name) && name != null) { if (string.IsNullOrEmpty(t)) t = voice.Key; vtpl.Append(name, t == voice.Key, host + $"lite/vcdn?kinopoisk_id={kinopoisk_id}&imdb_id={imdb_id}&rjson={rjson}&title={enc_title}&original_title={enc_original_title}&s={s}&t={voice.Key}"); } } #endregion if (string.IsNullOrEmpty(t)) t = "0"; var season = result.serial[t].First(i => i.id == s); if (season.folder == null) return default; var etpl = new EpisodeTpl(vtpl, season.folder.Length); foreach (var episode in season.folder) { var streamquality = new StreamQualityTpl(); foreach (Match m in Regex.Matches(episode.file ?? "", $"\\[(1080|720|480|360)p?\\]([^\\[\\|,\n\r\t ]+\\.(mp4|m3u8))")) { string link = m.Groups[2].Value; if (string.IsNullOrEmpty(link)) continue; if (usehls && !link.Contains(".m3u")) link += ":hls:manifest.m3u8"; else if (!usehls && link.Contains(".m3u")) link = link.Replace(":hls:manifest.m3u8", ""); streamquality.Insert(onstream($"{scheme}:{link}"), $"{m.Groups[1].Value}p"); } string e = episode.id.Split("_")[1]; etpl.Append($"{e} серия", title ?? original_title, s.ToString(), e, streamquality.Firts().link, streamquality: streamquality); } return etpl; } } catch { return default; } #endregion } } #endregion } }