using Shared.Engine.RxEnumerate; using Shared.Models.Base; using Shared.Models.Online.Kinobase; using Shared.Models.Online.Settings; using Shared.Models.Templates; using System.Text.Json; using System.Text.RegularExpressions; using System.Web; namespace Shared.Engine.Online { public struct KinobaseInvoke { #region KinobaseInvoke KinobaseSettings init; string host; string apihost; Func> onget; Func onstreamfile; Action requesterror; public KinobaseInvoke(string host, KinobaseSettings init, Func> onget, Func onstreamfile, Action requesterror = null) { this.init = init; this.host = host != null ? $"{host}/" : null; apihost = init.host; this.onget = onget; this.onstreamfile = onstreamfile; this.requesterror = requesterror; } #endregion #region Search async public Task Search(string title, int year) { if (string.IsNullOrEmpty(title)) return null; string content = await onget($"{apihost}/search?query={HttpUtility.UrlEncode(title)}"); if (content == null) { requesterror?.Invoke(); return null; } string link = null; var rx = Rx.Matches("
  • .*?
  • ", content, 0, RegexOptions.CultureInvariant | RegexOptions.Singleline); var similar = new SimilarTpl(rx.Count); foreach (var row in rx.Rows()) { if (row.Contains(">Трейлер")) continue; string name = row.Match("
    <[^>]+>([^<]+)"); string _year = row.Match("([0-9]+)"); string img = row.Match("]+(?:data-src|src)=\"/([^\"]+)\""); if (!string.IsNullOrEmpty(img)) img = $"{apihost}/{img}"; string rlnk = row.Match("href=\"/([^\"]+)\""); if (string.IsNullOrEmpty(rlnk) || string.IsNullOrEmpty(name)) continue; string uri = host + $"lite/kinobase?href={HttpUtility.UrlEncode(rlnk)}"; similar.Append(name, _year, string.Empty, uri, PosterApi.Size(img)); if (StringConvert.SearchName(name) == StringConvert.SearchName(title) && _year == year.ToString()) { if (string.IsNullOrEmpty(link)) link = rlnk; } } if (string.IsNullOrEmpty(link)) { if (!content.Contains(">По запросу") && similar.IsEmpty) { requesterror?.Invoke(); return null; } } return new SearchModel() { link = link, similar = similar }; } #endregion #region Embed async public Task Embed(string link, bool playerjs) { if (string.IsNullOrEmpty(link)) return null; string news = await onget($"{apihost}/{link}"); if (string.IsNullOrEmpty(news)) { requesterror?.Invoke(); return null; } if (playerjs) { try { string video = Regex.Match(news, "id=\"playerjsfile[^\"]*\">([^<]+)<").Groups[1].Value; if (string.IsNullOrEmpty(video)) { if (news.Contains("
    \\s*

    ([^<]+)

    "); return new EmbedModel() { IsEmpty = true, errormsg = h3Match.Success ? h3Match.Groups[1].Value.Trim() : "Ошибка alert" }; } return null; } if (video.EndsWith("]")) { var res = JsonSerializer.Deserialize(video); if (res == null || res.Length == 0) return null; return new EmbedModel() { serial = res, quality = (video.Contains("2160.") || video.Contains("2160_")) ? "2160p" : (video.Contains("1440.") || video.Contains("1440_")) ? "1440p" : (video.Contains("1080.") || video.Contains("1080_")) ? "1080p" : video.Contains("720.") ? "720p" : video.Contains("480.") ? "480p" : "360p" }; } else { return new EmbedModel() { content = video }; } } catch { return null; } } else { #region uppod.js if (news.Contains("id=\"playlists\"")) { try { string video = Regex.Match(news, "id=\"playlists\">([^<]+)<").Groups[1].Value; if (string.IsNullOrEmpty(video)) { requesterror?.Invoke(); return null; } var res = JsonSerializer.Deserialize(video); if (res == null || res.Length == 0) return null; return new EmbedModel() { serial = res, quality = video.Contains("1080.") ? "1080p" : video.Contains("720.") ? "720p" : video.Contains("480.") ? "480p" : "360p" }; } catch { return null; } } else { string video = StringConvert.FindLastText(news, "id=\"videoplayer\"", "
    "); if (string.IsNullOrEmpty(video)) { requesterror?.Invoke(); return null; } return new EmbedModel() { content = video }; } #endregion } } #endregion #region Tpl public ITplResult Tpl(EmbedModel md, string title, string href, int s, string t, bool rjson = false) { if (md == null || md.IsEmpty) return default; if (md.content != null) { #region Фильм var mtpl = new MovieTpl(title); if (init.playerjs) { if (md.content.Contains("{")) { var voices = md.content.Split("{"); var hash = new HashSet(20); foreach (string line in voices) { string voice = Regex.Match(line, "([^\\}]+)\\}").Groups[1].Value.Trim(); if (!string.IsNullOrEmpty(voice) && !hash.Contains(voice)) { hash.Add(voice); var streamquality = new StreamQualityTpl(); foreach (string q in new string[] { "2160", "1440", "1080", "720", "480", "360" }) { foreach (var line2 in voices) { if (line2.Contains(voice) && (line2.Contains($"_{q}") || line2.Contains($"_{q}"))) { string links = Regex.Match(line2, "\\}([^\\[,;]+)").Groups[1].Value; if (string.IsNullOrEmpty(links)) continue; streamquality.Append(onstreamfile.Invoke(links), $"{q}p"); } } } mtpl.Append(voice, streamquality.Firts().link, streamquality: streamquality); } } } else { var streamquality = new StreamQualityTpl(); foreach (string q in new string[] { "2160", "1440", "1080", "720", "480", "360" }) { string link = Regex.Match(md.content, $"\\[{q}p\\]([^\\[,; ]+)").Groups[1].Value; if (string.IsNullOrEmpty(link)) continue; streamquality.Append(onstreamfile.Invoke(link), $"{q}p"); } mtpl.Append("По умолчанию", streamquality.Firts().link, streamquality: streamquality); } } else { var streamquality = new StreamQualityTpl(); foreach (string q in new string[] { "1080", "720", "480", "360" }) { string link = Regex.Match(md.content, $"(https?://[^\"\\[\\|,;\n\r\t ]+_{q}(_10)?.(mp4|m3u8))").Groups[1].Value; if (string.IsNullOrEmpty(link)) continue; streamquality.Append(onstreamfile.Invoke(link), $"{q}p"); } var first = streamquality.Firts(); mtpl.Append(first.quality, first.link, streamquality: streamquality); } return mtpl; #endregion } else { #region Сериал string enc_title = HttpUtility.UrlEncode(title); string sArhc = s.ToString(); if (init.playerjs) { if (md.serial.First().folder == null) { if (s == -1) { var tpl = new SeasonTpl(md.quality); string link = host + $"lite/kinobase?title={enc_title}&href={HttpUtility.UrlEncode(href)}&t={HttpUtility.UrlEncode(t)}&s=1"; tpl.Append("1 сезон", link, 1); return tpl; } else { return renderSeason(md.serial, host, onstreamfile); } } else { if (s == -1) { var tpl = new SeasonTpl(md.quality); foreach (var item in md.serial) { string season = Regex.Match(item.title.Trim(), "^([0-9]+)").Groups[1].Value; string link = host + $"lite/kinobase?title={enc_title}&href={HttpUtility.UrlEncode(href)}&t={HttpUtility.UrlEncode(t)}&s={season}"; tpl.Append($"{season} сезон", link, season); } return tpl; } else { return renderSeason(md.serial.First(i => i.title.StartsWith($"{s} ")).folder, host, onstreamfile); } } ITplResult renderSeason(Season[] episodes, string host, Func onstreamfile) { #region Перевод var vtpl = new VoiceTpl(); { var hash_voices = new HashSet(); var m = Regex.Match(episodes.First().file, "\\{([^\\}]+)"); while (m.Success) { string voice = m.Groups[1].Value.Trim(); if (!hash_voices.Contains(voice)) { hash_voices.Add(voice); if (string.IsNullOrEmpty(t)) t = voice; string link = host + $"lite/kinobase?title={enc_title}&href={HttpUtility.UrlEncode(href)}&t={HttpUtility.UrlEncode(voice)}&s={s}"; bool active = t == voice; vtpl.Append(voice, active, link); } m = m.NextMatch(); } } #endregion var etpl = new EpisodeTpl(vtpl, episodes.Length); foreach (var episode in episodes) { if (string.IsNullOrEmpty(episode.file) || (t != null && !episode.file.Contains(t))) continue; var streamquality = new StreamQualityTpl(); foreach (string quality in new List { "2160", "1440", "1080", "720", "480", "360" }) { string qline = Regex.Match(episode.file, $"\\[{quality}p( [^\\]]+)?\\]([^\\[]+)").Groups[2].Value; if (string.IsNullOrEmpty(qline)) continue; if (string.IsNullOrEmpty(t)) { string links = Regex.Match(qline, "({[^\\}]+})?([^\\}\\{\\[,;]+)").Groups[2].Value; if (string.IsNullOrEmpty(links)) continue; streamquality.Append(onstreamfile.Invoke(links), $"{quality}p"); } else { string links = Regex.Match(qline, "{" + Regex.Escape(t) + "}" + "([^,;]+)").Groups[1].Value; if (string.IsNullOrEmpty(links)) continue; streamquality.Append(onstreamfile.Invoke(links), $"{quality}p"); } } #region subtitle var subtitles = new SubtitleTpl(); if (!string.IsNullOrEmpty(episode.subtitle)) { var m = Regex.Match(episode.subtitle, "\\[([^\\]]+)\\]([^\t ]+)"); while (m.Success) { subtitles.Append(m.Groups[1].Value, onstreamfile.Invoke(m.Groups[2].Value)); m = m.NextMatch(); } } #endregion etpl.Append(episode.title, title, sArhc, Regex.Match(episode.title, "^([0-9]+)").Groups[1].Value, streamquality.Firts().link, subtitles: subtitles, streamquality: streamquality); } return etpl; } } else { #region uppod.js ITplResult finEpisode(Season[] data, Func onstreamfile) { var etpl = new EpisodeTpl(data.Length); foreach (var episode in data) { if (string.IsNullOrEmpty(episode.file)) continue; var streamquality = new StreamQualityTpl(); foreach (string quality in new List { "1080", "720", "480", "360" }) { string link = Regex.Match(episode.file, $"(https?://[^\"\\[\\|,;\n\r\t ]+_{quality}.(mp4|m3u8))").Groups[1].Value; if (string.IsNullOrEmpty(link)) continue; streamquality.Append(onstreamfile.Invoke(link), $"{quality}p"); } etpl.Append(episode.title, title, sArhc, Regex.Match(episode.title, "^([0-9]+)").Groups[1].Value, streamquality.Firts().link, streamquality: streamquality); } return etpl; } if (md.serial.First().folder == null) { if (s == -1) { var tpl = new SeasonTpl(md.quality); string link = host + $"lite/kinobase?title={enc_title}&href={HttpUtility.UrlEncode(href)}&s=1"; tpl.Append("1 сезон", link, 1); return tpl; } else { return finEpisode(md.serial, onstreamfile); } } else { if (s == -1) { var tpl = new SeasonTpl(md.quality); foreach (var item in md.serial) { string season = Regex.Match(item.title.Trim(), "^([0-9]+)").Groups[1].Value; string link = host + $"lite/kinobase?title={enc_title}&href={HttpUtility.UrlEncode(href)}&s={season}"; tpl.Append($"{season} сезон", link, season); } return tpl; } else { return finEpisode(md.serial.First(i => i.title.StartsWith($"{s} ")).folder, onstreamfile); } } #endregion } #endregion } } #endregion } }