Alexander 659fb65256
fix: lampac balancers (#10)
* Fix Kinobase

* Fix Videoseed

* Fix Vibix
2026-02-09 16:14:35 +03:00

465 lines
19 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<string, Task<string>> onget;
Func<string, string> onstreamfile;
Action requesterror;
public KinobaseInvoke(string host, KinobaseSettings init, Func<string, Task<string>> onget, Func<string, string> 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<SearchModel> 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("<li class=\"[^\"]*\\bitem\\b[^\"]*\">.*?</li>", content, 0, RegexOptions.CultureInvariant | RegexOptions.Singleline);
var similar = new SimilarTpl(rx.Count);
foreach (var row in rx.Rows())
{
if (row.Contains(">Трейлер</span>"))
continue;
string name = row.Match("<div class=\"title\"><[^>]+>([^<]+)");
string _year = row.Match("<span class=\"year\">([0-9]+)");
string img = row.Match("<img[^>]+(?: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<EmbedModel> 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("<div class=\"alert\""))
{
var h3Match = Regex.Match(news, "<div class=\"alert\">\\s*<h3>([^<]+)</h3>");
return new EmbedModel() { IsEmpty = true, errormsg = h3Match.Success ? h3Match.Groups[1].Value.Trim() : "Ошибка alert" };
}
return null;
}
if (video.EndsWith("]"))
{
var res = JsonSerializer.Deserialize<Season[]>(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<Season[]>(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\"", "</div>");
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<string>(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<string, string> onstreamfile)
{
#region Перевод
var vtpl = new VoiceTpl();
{
var hash_voices = new HashSet<string>();
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<string> { "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<string, string> 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<string> { "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
}
}