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

* Fix Videoseed

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

848 lines
34 KiB
C#
Raw 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 Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using Shared.Models.Online.Vibix;
using Microsoft.Playwright;
using Shared.PlaywrightCore;
namespace Online.Controllers
{
public class Vibix : BaseOnlineController
{
public Vibix() : base(AppInit.conf.Vibix) { }
static readonly string[] qualityCandidates = new[] { "1080", "720", "480" };
StreamQualityTpl buildStreamQuality(string file)
{
var streams = new StreamQualityTpl();
if (string.IsNullOrEmpty(file))
return streams;
foreach (string q in qualityCandidates)
{
var g = new Regex($"{q}p?\\](\\{{[^\\}}]+\\}})?(?<file>https?://[^,\t\\[\\;\\{{ ]+)").Match(file).Groups;
if (!string.IsNullOrEmpty(g["file"].Value))
streams.Append(HostStreamProxy(g["file"].Value), $"{q}p");
}
return streams;
}
[HttpGet]
[Route("lite/vibix")]
async public Task<ActionResult> Index(string imdb_id, long kinopoisk_id, string title, string original_title, int s = -1, bool rjson = false, int voiceover = 0)
{
if (await IsRequestBlocked(rch: true))
return badInitMsg;
if (string.IsNullOrEmpty(init.token))
return OnError();
string enc_title = HttpUtility.UrlEncode(title);
string enc_original_title = HttpUtility.UrlEncode(original_title);
if (!hybridCache.TryGetValue($"vibix:v2:view:{kinopoisk_id}:{imdb_id}", out (Dictionary<string, JObject> seasons, string iframe) v2Cache))
{
v2Cache = await searchV2(imdb_id, kinopoisk_id);
if (v2Cache.seasons != null || !string.IsNullOrEmpty(v2Cache.iframe))
hybridCache.Set($"vibix:v2:view:{kinopoisk_id}:{imdb_id}", v2Cache, cacheTime(40));
}
if (v2Cache.seasons != null)
{
if (PlaywrightBrowser.Status == PlaywrightStatus.disabled)
return OnError();
#region Сериал
if (s == -1)
{
var tpl = new SeasonTpl(v2Cache.seasons.Count);
foreach (var season in v2Cache.seasons)
{
string link = $"{host}/lite/vibix?rjson={rjson}&kinopoisk_id={kinopoisk_id}&imdb_id={imdb_id}&title={enc_title}&original_title={enc_original_title}&s={season.Key}";
tpl.Append($"{season.Key} сезон", link, season.Key);
}
return await ContentTpl(tpl);
}
else
{
string sArhc = s.ToString();
var videos = v2Cache.seasons.First(i => i.Key == sArhc).Value["videos"].ToObject<Dictionary<string, JObject>>();
var etpl = new EpisodeTpl(videos.Count);
foreach (var video in videos)
{
string iframe = addIframeArgs(video.Value.Value<string>("iframe"));
etpl.Append($"{video.Key} серия", title ?? original_title, sArhc, video.Key, accsArgs($"{host}/lite/vibix/video/{AesTo.Encrypt(buildVideoPayload(iframe, null))}"), "call", vast: init.vast);
}
return await ContentTpl(etpl);
}
#endregion
}
var data = await search(imdb_id, kinopoisk_id);
if (data == null)
return OnError();
if (data.type == "serial" && PlaywrightBrowser.Status != PlaywrightStatus.disabled && !string.IsNullOrEmpty(data.embed_code))
{
var serials = await getSerials(imdb_id, kinopoisk_id);
if (serials?.seasons == null)
return OnError();
int defaultVoiceover = data.voiceovers?.FirstOrDefault()?.id ?? 0;
int activeVoiceover = voiceover > 0 ? voiceover : defaultVoiceover;
VoiceTpl? vtpl = null;
if (data.voiceovers != null && data.voiceovers.Length > 0)
{
var voices = new VoiceTpl(data.voiceovers.Length);
foreach (var voice in data.voiceovers)
{
string link = $"{host}/lite/vibix?rjson={rjson}&kinopoisk_id={kinopoisk_id}&imdb_id={imdb_id}&title={enc_title}&original_title={enc_original_title}&s={s}&voiceover={voice.id}";
voices.Append(voice.name, voice.id == activeVoiceover, link);
}
vtpl = voices;
}
if (s == -1)
{
var tpl = new SeasonTpl(serials.seasons.Length);
for (int i = 0; i < serials.seasons.Length; i++)
{
int seasonNumber = i + 1;
string link = $"{host}/lite/vibix?rjson={rjson}&kinopoisk_id={kinopoisk_id}&imdb_id={imdb_id}&title={enc_title}&original_title={enc_original_title}&s={seasonNumber}&voiceover={activeVoiceover}";
tpl.Append($"{seasonNumber} сезон", link, seasonNumber);
}
return await ContentTpl(tpl);
}
else
{
int seasonIndex = s - 1;
if (seasonIndex < 0 || seasonIndex >= serials.seasons.Length)
return OnError();
var season = serials.seasons[seasonIndex];
var etpl = new EpisodeTpl(vtpl, season.series?.Length ?? 0);
if (season.series != null)
{
foreach (var episode in season.series)
{
string embed = applyEmbedArgs(data.embed_code, s.ToString(), episode.id.ToString(), activeVoiceover);
etpl.Append(episode.name ?? $"{episode.id} серия", title ?? original_title, s.ToString(), episode.id.ToString(), accsArgs($"{host}/lite/vibix/video/{AesTo.Encrypt(buildVideoPayload(null, embed))}"), "call", vast: init.vast);
}
}
return await ContentTpl(etpl);
}
}
if (data.type == "movie" && PlaywrightBrowser.Status != PlaywrightStatus.disabled && !string.IsNullOrEmpty(data.iframe_url))
{
var mtpl = new MovieTpl(title, original_title, 1);
string iframe = addIframeArgs(data.iframe_url);
if (data.voiceovers != null && data.voiceovers.Length > 0)
{
int defaultVoiceover = data.voiceovers.FirstOrDefault()?.id ?? 0;
int activeVoiceover = voiceover > 0 ? voiceover : defaultVoiceover;
foreach (var voice in data.voiceovers)
{
string embed = applyEmbedArgs(data.embed_code, null, null, voice.id);
mtpl.Append(voice.name, accsArgs($"{host}/lite/vibix/video/{AesTo.Encrypt(buildVideoPayload(iframe, embed))}") + "#.m3u8", "call", voice_name: voice.name, vast: init.vast);
}
}
else
{
mtpl.Append("По-умолчанию", accsArgs($"{host}/lite/vibix/video/{AesTo.Encrypt(buildVideoPayload(iframe, data.embed_code))}") + "#.m3u8", "call", vast: init.vast);
}
return await ContentTpl(mtpl);
}
rhubFallback:
var cache = await InvokeCacheResult<EmbedModel>(ipkey($"vibix:iframe:{data.iframe_url}"), 20, async e =>
{
string domain = getFrontendDomain();
string api_url = data.iframe_url
.Replace("/embed/", "/api/v1/embed/")
.Replace("/embed-serials/", "/api/v1/embed-serials/");
api_url += $"?iframe_url={HttpUtility.UrlEncode(data.iframe_url)}";
api_url += $"&kp={CrypTo.unic(6).ToLower()}";
api_url += $"&domain={domain}&parent_domain={domain}";
var api_headers = HeadersModel.Init(
("accept", "*/*"),
("accept-language", "ru-RU,ru;q=0.9,uk-UA;q=0.8,uk;q=0.7,en-US;q=0.6,en;q=0.5"),
("sec-fetch-dest", "empty"),
("sec-fetch-mode", "cors"),
("sec-fetch-site", "same-origin"),
("referer", data.iframe_url)
);
var root = await httpHydra.Get<JObject>(api_url, addheaders: api_headers);
if (root == null || !root.ContainsKey("data") || root["data"]?["playlist"] == null)
return e.Fail("root", refresh_proxy: true);
return e.Success(new EmbedModel() { playlist = root["data"]["playlist"].ToObject<Seasons[]>() });
});
if (IsRhubFallback(cache))
goto rhubFallback;
if (data.type == "movie")
{
#region Фильм
return await ContentTpl(cache, () =>
{
var mtpl = new MovieTpl(title, original_title, 1);
foreach (var movie in cache.Value.playlist)
{
var streams = buildStreamQuality(movie.file);
mtpl.Append(movie.title, streams.Firts().link, streamquality: streams, vast: init.vast);
}
return mtpl;
});
#endregion
}
else
{
#region Сериал
return await ContentTpl(cache, () =>
{
if (s == -1)
{
var tpl = new SeasonTpl(cache.Value.playlist.Length);
foreach (var season in cache.Value.playlist)
{
string name = season.title;
if (int.TryParse(Regex.Match(name, "([0-9]+)$").Groups[1].Value, out int _s) && _s > 0)
{
string link = $"{host}/lite/vibix?rjson={rjson}&kinopoisk_id={kinopoisk_id}&imdb_id={imdb_id}&title={enc_title}&original_title={enc_original_title}&s={_s}";
tpl.Append($"{_s} сезон", link, _s);
}
}
return tpl;
}
else
{
var etpl = new EpisodeTpl();
string sArhc = s.ToString();
foreach (var season in cache.Value.playlist)
{
if (!season.title.EndsWith($" {s}"))
continue;
foreach (var episode in season.folder)
{
string name = episode.title;
string file = episode.folder?.First().file ?? episode.file;
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(file))
continue;
var streams = buildStreamQuality(file);
etpl.Append(name, title ?? original_title, sArhc, Regex.Match(name, "([0-9]+)").Groups[1].Value, streams.Firts().link, streamquality: streams, vast: init.vast);
}
}
return etpl;
}
});
#endregion
}
}
string addIframeArgs(string iframe)
{
if (string.IsNullOrEmpty(iframe))
return iframe;
if (iframe.Contains("domain=") || iframe.Contains("parent_domain="))
return iframe;
string delimiter = iframe.Contains("?") ? "&" : "?";
string domain = getFrontendDomain();
return $"{iframe}{delimiter}domain={domain}&parent_domain={domain}";
}
string buildVideoPayload(string iframe, string embed)
{
if (string.IsNullOrEmpty(embed))
return iframe;
return JObject.FromObject(new
{
iframe,
embed
}).ToString();
}
string buildEmbedHtml(string embedCode)
{
if (string.IsNullOrEmpty(embedCode))
return null;
embedCode = normalizeEmbedCode(embedCode);
return $@"<!doctype html>
<html>
<head>
<meta name=""viewport"" content=""width=device-width, initial-scale=1"">
<script src=""https://graphicslab.io/sdk/v2/rendex-sdk.min.js""></script>
</head>
<body>
{embedCode}
</body>
</html>";
}
string applyEmbedArgs(string embedCode, string season, string episodes, int voiceover)
{
if (string.IsNullOrEmpty(embedCode))
return embedCode;
embedCode = normalizeEmbedCode(embedCode);
var attrs = new List<string>();
if (!string.IsNullOrEmpty(season) && !embedCode.Contains("data-season="))
attrs.Add($"data-season=\"{season}\"");
if (!string.IsNullOrEmpty(episodes) && !embedCode.Contains("data-episodes="))
attrs.Add($"data-episodes=\"{episodes}\"");
if (voiceover > 0 && !embedCode.Contains("data-voiceover="))
attrs.Add($"data-voiceover=\"{voiceover}\"");
if (voiceover > 0 && !embedCode.Contains("data-voiceover-only="))
attrs.Add("data-voiceover-only=\"true\"");
if (attrs.Count == 0)
return embedCode;
string insert = $"<ins {string.Join(" ", attrs)} ";
return Regex.Replace(embedCode, "<ins\\b", insert, RegexOptions.IgnoreCase);
}
string normalizeEmbedCode(string embedCode)
{
if (string.IsNullOrEmpty(embedCode))
return embedCode;
if (Regex.IsMatch(embedCode, "<ins\\b", RegexOptions.IgnoreCase))
return embedCode;
return $"<ins {embedCode}></ins>";
}
#region Video
[HttpGet]
[Route("lite/vibix/video/{*iframe}")]
async public ValueTask<ActionResult> Video(string iframe)
{
if (PlaywrightBrowser.Status == PlaywrightStatus.disabled)
return OnError();
if (await IsRequestBlocked(rch: true))
return badInitMsg;
string decrypted = AesTo.Decrypt(iframe);
if (string.IsNullOrEmpty(decrypted))
return OnError();
string embedCode = null;
string iframeUrl = decrypted;
if (decrypted.StartsWith("{"))
{
try
{
var payload = JObject.Parse(decrypted);
iframeUrl = payload.Value<string>("iframe");
embedCode = payload.Value<string>("embed");
}
catch { }
}
iframeUrl = addIframeArgs(iframeUrl);
if (string.IsNullOrEmpty(iframeUrl) && string.IsNullOrEmpty(embedCode))
return OnError();
string cacheKey = iframeUrl ?? CrypTo.md5(embedCode ?? string.Empty);
return await InvkSemaphore($"vibix:video:{cacheKey}:{proxyManager?.CurrentProxyIp}", async key =>
{
if (!hybridCache.TryGetValue(key, out (string location, StreamQualityTpl streamquality) cache))
{
int bestQuality = 0;
var streamquality = new StreamQualityTpl();
string referer = Regex.Match(iframeUrl ?? string.Empty, "(^https?://[^/]+)").Groups[1].Value;
if (string.IsNullOrEmpty(referer))
referer = $"https://{getFrontendDomain()}";
var headers = httpHeaders(init, HeadersModel.Init
(
("referer", referer)
));
TimeSpan? cacheTtl = null;
try
{
using (var browser = new PlaywrightBrowser(init.priorityBrowser))
{
var page = await browser.NewPageAsync(init.plugin, proxy: proxy_data, headers: headers?.ToDictionary()).ConfigureAwait(false);
if (page == null)
return OnError();
await page.AddInitScriptAsync(@"() => {
try {
localStorage.setItem('pljsquality', '1080p');
localStorage.setItem('ksquality', '1080p');
} catch (e) {}
}").ConfigureAwait(false);
await page.RouteAsync("**/api/v1/embed/**", async route =>
{
try
{
if (route.Request.Method != "GET")
{
await route.ContinueAsync();
return;
}
await route.ContinueAsync();
}
catch
{
await route.ContinueAsync();
}
});
await page.RouteAsync("**/*", async route =>
{
try
{
if (!string.IsNullOrEmpty(cache.location))
{
await route.AbortAsync();
return;
}
var reqUrl = route.Request.Url;
if (reqUrl.Contains("/hls/", StringComparison.OrdinalIgnoreCase) &&
reqUrl.Contains("/seg-", StringComparison.OrdinalIgnoreCase) &&
reqUrl.Contains(".ts", StringComparison.OrdinalIgnoreCase))
{
var playlist = Regex.Replace(reqUrl, @"/seg-[^/?]+\.ts", "/index.m3u8", RegexOptions.IgnoreCase);
updateCacheTtl(ref cacheTtl, reqUrl);
updateLocation(ref cache.location, ref bestQuality, playlist, streamquality);
}
if (reqUrl.IndexOf(".m3u8", StringComparison.OrdinalIgnoreCase) >= 0 ||
(reqUrl.IndexOf(".mp4", StringComparison.OrdinalIgnoreCase) >= 0 &&
reqUrl.IndexOf(".ts", StringComparison.OrdinalIgnoreCase) < 0))
{
updateCacheTtl(ref cacheTtl, reqUrl);
updateLocation(ref cache.location, ref bestQuality, reqUrl, streamquality);
}
if (await PlaywrightBase.AbortOrCache(page, route, abortMedia: true, fullCacheJS: true))
return;
await route.ContinueAsync();
}
catch { }
});
var options = new PageGotoOptions()
{
Timeout = 15_000,
WaitUntil = WaitUntilState.NetworkIdle
};
IResponse result = null;
try
{
await page.GotoAsync("https://cm.vibix.biz", new PageGotoOptions()
{
Timeout = 10_000,
WaitUntil = WaitUntilState.DOMContentLoaded
}).ConfigureAwait(false);
}
catch { }
if (!string.IsNullOrEmpty(embedCode))
{
try
{
await page.SetContentAsync(buildEmbedHtml(embedCode), new PageSetContentOptions()
{
Timeout = 15_000,
WaitUntil = WaitUntilState.NetworkIdle
}).ConfigureAwait(false);
}
catch { }
}
else if (!string.IsNullOrEmpty(iframeUrl))
{
try
{
await page.SetContentAsync(PlaywrightBase.IframeHtml(iframeUrl), new PageSetContentOptions()
{
Timeout = 15_000,
WaitUntil = WaitUntilState.NetworkIdle
}).ConfigureAwait(false);
}
catch { }
}
if (string.IsNullOrEmpty(cache.location) && !string.IsNullOrEmpty(iframeUrl))
result = await page.GotoAsync(iframeUrl, options).ConfigureAwait(false);
if (result != null)
{
try
{
await page.EvaluateAsync(@"() => {
const video = document.querySelector('video');
if (video) {
video.muted = true;
video.play().catch(() => {});
}
const btn = document.querySelector('.vjs-big-play-button, .plyr__control--overlaid, .jw-icon-playback, .jw-icon-play');
if (btn) btn.click();
}").ConfigureAwait(false);
}
catch { }
}
if (string.IsNullOrEmpty(cache.location))
await page.WaitForTimeoutAsync(3000).ConfigureAwait(false);
if (result != null && string.IsNullOrEmpty(cache.location))
{
string html = await page.ContentAsync().ConfigureAwait(false);
cache.location = Regex.Match(html, "<video preload=\"none\" src=\"(https?://[^\"]+)\"").Groups[1].Value;
if (!cache.location.Contains(".m3u") && !cache.location.Contains(".mp4"))
cache.location = null;
}
PlaywrightBase.WebLog("SET", iframe, cache.location, proxy_data);
}
if (string.IsNullOrEmpty(cache.location))
{
proxyManager?.Refresh();
return OnError();
}
}
catch
{
return OnError();
}
proxyManager?.Success();
cache.streamquality = streamquality;
hybridCache.Set(key, cache, resolveCacheTtl(cacheTtl, cacheTime(20)));
}
string refererStream = Regex.Match(iframeUrl ?? string.Empty, "(^https?://[^/]+)").Groups[1].Value;
if (string.IsNullOrEmpty(refererStream))
refererStream = "https://cm.vibix.biz";
var headers_stream = httpHeaders(init.corsHost(), HeadersModel.Join(HeadersModel.Init("referer", refererStream), init.headers_stream));
string link = HostStreamProxy(cache.location, headers: headers_stream);
var streamQuality = cache.streamquality;
bool hasQualities = false;
try
{
if (streamQuality.Any())
hasQualities = true;
}
catch { }
if (!hasQualities)
return ContentTo(VideoTpl.ToJson("play", link, "auto", vast: init.vast));
return ContentTo(VideoTpl.ToJson("play", streamQuality.Firts().link, "auto", streamquality: streamQuality, vast: init.vast));
});
}
#endregion
void updateLocation(ref string location, ref int bestQuality, string candidate, StreamQualityTpl streamquality)
{
if (string.IsNullOrEmpty(candidate))
return;
int q = getQualityFromUrl(candidate);
if (q == 0)
{
if (tryExpandQualityVariants(candidate, streamquality, ref bestQuality, ref location))
return;
if (string.IsNullOrEmpty(location))
location = candidate;
return;
}
streamquality.Append(HostStreamProxy(candidate), $"{q}p");
if (q > bestQuality)
{
bestQuality = q;
location = candidate;
}
}
bool tryExpandQualityVariants(string candidate, StreamQualityTpl streamquality, ref int bestQuality, ref string location)
{
var match = Regex.Match(candidate, "/hls/\\d+/\\d+/(?<id>\\d+)\\.mp4/index\\.m3u8", RegexOptions.IgnoreCase);
if (!match.Success)
return false;
string id = match.Groups["id"].Value;
int endIdx = candidate.IndexOf($"{id}.mp4/index.m3u8", StringComparison.OrdinalIgnoreCase);
if (endIdx < 0)
return false;
string prefix = candidate.Substring(0, endIdx);
string suffix = candidate.Substring(endIdx + $"{id}.mp4/index.m3u8".Length);
foreach (int quality in new[] { 1080, 720, 480 })
{
string variant = $"{prefix}{id}_{quality}p.mp4/index.m3u8{suffix}";
streamquality.Append(HostStreamProxy(variant), $"{quality}p");
if (quality > bestQuality)
{
bestQuality = quality;
location = variant;
}
}
return true;
}
int getQualityFromUrl(string url)
{
if (string.IsNullOrEmpty(url))
return 0;
var match = Regex.Match(url, "(2160|1440|1080|720|480|360|240)p", RegexOptions.IgnoreCase);
if (match.Success && int.TryParse(match.Groups[1].Value, out int q))
return q;
return 0;
}
void updateCacheTtl(ref TimeSpan? cacheTtl, string url)
{
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return;
var query = HttpUtility.ParseQueryString(uri.Query);
if (!long.TryParse(query["expires"], out long expires))
return;
DateTimeOffset expiresAt;
try
{
expiresAt = expires > 9999999999 ? DateTimeOffset.FromUnixTimeMilliseconds(expires) : DateTimeOffset.FromUnixTimeSeconds(expires);
}
catch
{
return;
}
var ttl = expiresAt - DateTimeOffset.UtcNow - TimeSpan.FromSeconds(45);
if (ttl <= TimeSpan.Zero)
return;
if (ttl < TimeSpan.FromSeconds(30))
ttl = TimeSpan.FromSeconds(30);
if (!cacheTtl.HasValue || ttl < cacheTtl.Value)
cacheTtl = ttl;
}
TimeSpan resolveCacheTtl(TimeSpan? cacheTtl, TimeSpan fallback)
{
if (!cacheTtl.HasValue)
return fallback;
if (cacheTtl.Value <= TimeSpan.Zero)
return TimeSpan.FromSeconds(1);
return cacheTtl.Value < fallback ? cacheTtl.Value : fallback;
}
string getFrontendDomain()
{
if (Uri.TryCreate(host, UriKind.Absolute, out var uri) && !string.IsNullOrEmpty(uri.Host))
return uri.Host;
if (Uri.TryCreate($"https://{host}", UriKind.Absolute, out var fallback) && !string.IsNullOrEmpty(fallback.Host))
return fallback.Host;
return "cm.vibix.biz";
}
#region search
async ValueTask<Video> search(string imdb_id, long kinopoisk_id)
{
string memKey = $"vibix:view:{kinopoisk_id}:{imdb_id}";
if (!hybridCache.TryGetValue(memKey, out Video root))
{
root = await goSearch(null, kinopoisk_id) ?? await goSearch(imdb_id, 0);
if (root == null)
return null;
proxyManager?.Success();
hybridCache.Set(memKey, root, cacheTime(30));
}
return root;
}
async Task<Video> goSearch(string imdb_id, long kinopoisk_id)
{
if (string.IsNullOrEmpty(imdb_id) && kinopoisk_id == 0)
return null;
string uri = kinopoisk_id > 0 ? $"kp/{kinopoisk_id}" : $"imdb/{imdb_id}";
var video = await httpHydra.Get<Video>($"{init.host}/api/v1/publisher/videos/{uri}", safety: true, addheaders: HeadersModel.Init(
("Accept", "application/json"),
("Authorization", $"Bearer {init.token}"),
("X-CSRF-TOKEN", "")
));
if (video == null)
{
proxyManager?.Refresh();
return null;
}
if (string.IsNullOrEmpty(video.type))
return null;
if (string.IsNullOrEmpty(video.iframe_url) || !video.iframe_url.Contains("token="))
{
string iframe = getIframeFromEmbed(video.embed_code);
if (!string.IsNullOrEmpty(iframe))
video.iframe_url = iframe;
}
if (string.IsNullOrEmpty(video.iframe_url))
return null;
return video;
}
#endregion
#region serials
async Task<SerialsRoot> getSerials(string imdb_id, long kinopoisk_id)
{
if (string.IsNullOrEmpty(imdb_id) && kinopoisk_id == 0)
return null;
string uri = kinopoisk_id > 0 ? $"kp/{kinopoisk_id}" : $"imdb/{imdb_id}";
var serials = await httpHydra.Get<SerialsRoot>($"{init.host}/api/v1/serials/{uri}", safety: true, addheaders: HeadersModel.Init(
("Accept", "application/json"),
("Authorization", $"Bearer {init.token}"),
("X-CSRF-TOKEN", "")
));
if (serials?.seasons == null)
{
proxyManager?.Refresh();
return null;
}
proxyManager?.Success();
return serials;
}
#endregion
string getIframeFromEmbed(string embed)
{
if (string.IsNullOrEmpty(embed))
return null;
string iframe = Regex.Match(embed, "src=[\"'](?<url>https?://[^\"']+)", RegexOptions.IgnoreCase).Groups["url"].Value;
if (!string.IsNullOrEmpty(iframe))
return iframe;
return null;
}
#region searchV2
async Task<(Dictionary<string, JObject> seasons, string iframe)> searchV2(string imdb_id, long kinopoisk_id)
{
string imdbArg = !string.IsNullOrEmpty(imdb_id) ? $"&imdb={imdb_id}" : null;
string kpArg = kinopoisk_id > 0 ? $"&kp={kinopoisk_id}" : null;
JToken data = null;
foreach (var candidate in new (string item, string arg)[] { ("movie", kpArg), ("movie", imdbArg), ("serial", kpArg), ("serial", imdbArg) })
{
data = await goSearchV2(candidate.item, candidate.arg);
if (data != null)
break;
}
if (data == null)
return (null, null);
string iframe = data.Value<string>("iframe");
var seasons = data["seasons"]?.ToObject<Dictionary<string, JObject>>();
if (string.IsNullOrEmpty(iframe) && seasons == null)
return (null, null);
proxyManager?.Success();
return (seasons, iframe);
}
async Task<JToken> goSearchV2(string item, string arg)
{
if (string.IsNullOrEmpty(arg))
return null;
long kp = 0;
string imdb = null;
if (arg.StartsWith("&kp=", StringComparison.OrdinalIgnoreCase))
long.TryParse(arg[4..], out kp);
else if (arg.StartsWith("&imdb=", StringComparison.OrdinalIgnoreCase))
imdb = arg[6..];
var video = await goSearch(imdb, kp);
if (video == null || !string.Equals(video.type, item, StringComparison.OrdinalIgnoreCase))
return null;
if (string.IsNullOrEmpty(video.iframe_url))
return null;
return new JObject
{
["iframe"] = video.iframe_url
};
}
#endregion
}
}