using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Shared.Models.Events; using Shared.Models.Module; using Shared.Models.Module.Entrys; using Shared.Models.SQL; using Shared.PlaywrightCore; using System.Data; using System.Text; using IO = System.IO; namespace Online.Controllers { public class OnlineApiController : BaseController { #region online.js [HttpGet] [AllowAnonymous] [Route("online.js")] [Route("online/js/{token}")] public ContentResult Online(string token) { var init = AppInit.conf.online; var apr = init.appReplace ?? InvkEvent.conf?.Controller?.AppReplace?.online?.regex; string memKey = $"online.js:{apr?.Count ?? 0}:{InvkEvent.conf?.Controller?.AppReplace?.online?.list?.Count ?? 0}:{init.version}:{init.description}:{init.apn}:{host}:{init.spider}:{init.component}:{init.name}:{init.spiderName}"; if (!memoryCache.TryGetValue(memKey, out (string file, string filecleaer) cache)) { cache.file = FileCache.ReadAllText("plugins/online.js", saveCache: false) .Replace("{rch_websoket}", FileCache.ReadAllText($"plugins/rch_{AppInit.conf.WebSocket.type}.js", saveCache: false)); string playerinner = FileCache.ReadAllText("plugins/player-inner.js", saveCache: false) .Replace("{useplayer}", (!string.IsNullOrEmpty(AppInit.conf.playerInner)).ToString().ToLower()) .Replace("{notUseTranscoding}", (AppInit.conf.transcoding.enable == false).ToString().ToLower()); #region appReplace if (apr != null) { foreach (var r in apr) { string val = r.Value; if (val.StartsWith("file:")) val = IO.File.ReadAllText(val.Substring(5)); cache.file = Regex.Replace(cache.file, r.Key, val, RegexOptions.IgnoreCase); } } if (InvkEvent.conf?.Controller?.AppReplace?.online?.list != null) { foreach (var r in InvkEvent.conf.Controller.AppReplace.online.list) { string val = r.Value; if (val.StartsWith("file:")) val = IO.File.ReadAllText(val.Substring(5)); cache.file = cache.file.Replace(r.Key, val); } } #endregion if (!init.version) { cache.file = Regex.Replace(cache.file, "version: \\'[^\\']+\\'", "version: ''") .Replace("manifst.name, \" v\"", "manifst.name, \" \""); } if (init.description != "Плагин для просмотра онлайн сериалов и фильмов") cache.file = Regex.Replace(cache.file, "description: \\'([^\\']+)?\\'", $"description: '{init.description}'"); if (init.apn != null) cache.file = Regex.Replace(cache.file, "apn: \\'([^\\']+)?\\'", $"apn: '{init.apn}'"); var bulder = new StringBuilder(cache.file); if (!init.spider) { bulder = bulder.Replace("addSourceSearch('Spider', 'spider');", "") .Replace("addSourceSearch('Anime', 'spider/anime');", ""); } if (init.component != "lampac") { bulder = bulder.Replace("component: 'lampac'", $"component: '{init.component}'") .Replace("'lampac', component", $"'{init.component}', component") .Replace("window.lampac_plugin", $"window.{init.component}_plugin"); } if (init.name != "Lampac") bulder = bulder.Replace("name: 'Lampac'", $"name: '{init.name}'"); if (init.spiderName != "Spider") { bulder = bulder.Replace("addSourceSearch('Spider'", $"addSourceSearch('{init.spiderName}'") .Replace("addSourceSearch('Anime'", $"addSourceSearch('{init.spiderName} - Anime'"); } bulder = bulder .Replace("{invc-rch}", FileCache.ReadAllText("plugins/invc-rch.js", saveCache: false)) .Replace("{invc-rch_nws}", FileCache.ReadAllText("plugins/invc-rch_nws.js", saveCache: false)) .Replace("{player-inner}", playerinner) .Replace("{localhost}", host); cache.file = bulder.ToString(); cache.filecleaer = cache.file.Replace("{token}", string.Empty); if (AppInit.conf.mikrotik == false) memoryCache.Set(memKey, cache, DateTime.Now.AddMinutes(1)); } if (InvkEvent.conf?.Controller?.AppReplace?.online?.eval != null) { string source = InvkEvent.AppReplace("online", new EventAppReplace(cache.file, token, null, host, requestInfo, HttpContext.Request, hybridCache)); return Content(source.Replace("{token}", HttpUtility.UrlEncode(token)), "application/javascript; charset=utf-8"); } return Content(token != null ? cache.file.Replace("{token}", HttpUtility.UrlEncode(token)) : cache.filecleaer, "application/javascript; charset=utf-8"); } #endregion #region lite.js [HttpGet] [AllowAnonymous] [Route("lite.js")] [Route("lite/js/{token}")] public ActionResult Lite(string token) { var sb = new StringBuilder(FileCache.ReadAllText("plugins/lite.js")); sb.Replace("{localhost}", $"{host}/lite") .Replace("{token}", HttpUtility.UrlEncode(token)); return Content(sb.ToString(), "application/javascript; charset=utf-8"); } #endregion #region externalids /// /// imdb_id, kinopoisk_id /// static ConcurrentDictionary externalids = new ConcurrentDictionary(); static DateTime externalids_lastWriteTime = default, externalids_nextCheck = default; [HttpGet] [Route("externalids")] async public ValueTask Externalids(string id, string imdb_id, long kinopoisk_id, int serial) { #region load externalids if (IO.File.Exists("data/externalids.json")) { try { if (externalids_nextCheck > DateTime.Now || externalids_nextCheck == default) { lock (externalids) { externalids_nextCheck = DateTime.Now.AddMinutes(5); var lastWriteTime = IO.File.GetLastWriteTime("data/externalids.json"); if (lastWriteTime != externalids_lastWriteTime) { externalids_lastWriteTime = lastWriteTime; foreach (var item in JsonConvert.DeserializeObject>(IO.File.ReadAllText("data/externalids.json"))) externalids.AddOrUpdate(item.Key, item.Value, (k, v) => item.Value); } } } } catch { } } #endregion #region KP_ if (id != null && id.StartsWith("KP_")) { string _kp = id.Substring(0, 3); foreach (var eid in externalids) { if (eid.Value == _kp && !string.IsNullOrEmpty(eid.Key)) { imdb_id = eid.Key; break; } } if (!string.IsNullOrEmpty(imdb_id)) { return Json(new { imdb_id, kinopoisk_id = _kp }); } else { string mkey = $"externalids:KP_:{_kp}"; if (!hybridCache.TryGetValue(mkey, out string _imdbid, inmemory: false)) { string json = await Http.Get($"https://api.alloha.tv/?token=04941a9a3ca3ac16e2b4327347bbc1&kp=" + _kp, timeoutSeconds: 5); _imdbid = Regex.Match(json ?? "", "\"id_imdb\":\"(tt[^\"]+)\"").Groups[1].Value; hybridCache.Set(mkey, _imdbid, DateTime.Now.AddHours(8), inmemory: false); } return Json(new { imdb_id = _imdbid, kinopoisk_id = _kp }); } } #endregion #region getAlloha / getVSDN / getTabus async Task getAlloha(string imdb) { var proxyManager = new ProxyManager("alloha", AppInit.conf.Alloha); string json = await Http.Get("https://api.alloha.tv/?token=04941a9a3ca3ac16e2b4327347bbc1&imdb=" + imdb, timeoutSeconds: 5, proxy: proxyManager.Get()); if (json == null) return null; string kpid = Regex.Match(json, "\"id_kp\":([0-9]+),").Groups[1].Value; if (!string.IsNullOrEmpty(kpid) && kpid != "0" && kpid != "null") return kpid; return null; } async Task getVSDN(string imdb) { if (AppInit.conf.Lumex.spider && AppInit.conf.mikrotik == false) { long? res = Lumex.database.FirstOrDefault(i => i.imdb_id == imdb).kinopoisk_id; if (res > 0) return res.ToString(); } if (string.IsNullOrEmpty(AppInit.conf.VideoCDN.token) || string.IsNullOrEmpty(AppInit.conf.VideoCDN.iframehost)) return null; var proxyManager = new ProxyManager("videocdn", AppInit.conf.VideoCDN); string json = await Http.Get($"{AppInit.conf.VideoCDN.iframehost}/api/short?api_token={AppInit.conf.VideoCDN.token}&imdb_id={imdb}", timeoutSeconds: 5, proxy: proxyManager.Get()); if (json == null) return null; string kpid = Regex.Match(json, "\"kp_id\":\"?([0-9]+)\"?").Groups[1].Value; if (!string.IsNullOrEmpty(kpid) && kpid != "0" && kpid != "null") return kpid; return null; } async Task getTabus(string imdb) { var proxyManager = new ProxyManager("collaps", AppInit.conf.Collaps); string json = await Http.Get("https://api.bhcesh.me/franchise/details?token=d39edcf2b6219b6421bffe15dde9f1b3&imdb_id=" + imdb.Remove(0, 2), timeoutSeconds: 5, proxy: proxyManager.Get()); if (json == null) return null; string kpid = Regex.Match(json, "\"kinopoisk_id\":\"?([0-9]+)\"?").Groups[1].Value; if (!string.IsNullOrEmpty(kpid) && kpid != "0" && kpid != "null") return kpid; return null; } #endregion #region get imdb_id if (string.IsNullOrWhiteSpace(imdb_id)) { if (kinopoisk_id > 0) { string kinopoisk_id_str = kinopoisk_id.ToString(); foreach (var eid in externalids) { if (eid.Value == kinopoisk_id_str && !string.IsNullOrEmpty(eid.Key)) { imdb_id = eid.Key; break; } } } if (string.IsNullOrWhiteSpace(imdb_id) && long.TryParse(id, out long _testid) && _testid > 0) { using (var sqlDb = ExternalidsContext.Factory != null ? ExternalidsContext.Factory.CreateDbContext() : new ExternalidsContext()) { imdb_id = sqlDb.imdb.Find($"{id}_{serial}")?.value; } if (string.IsNullOrEmpty(imdb_id)) { string mkey = $"externalids:locktmdb:{serial}:{id}"; if (!memoryCache.TryGetValue(mkey, out _)) { memoryCache.Set(mkey, 0, DateTime.Now.AddHours(1)); string cat = serial == 1 ? "tv" : "movie"; var header = HeadersModel.Init(("localrequest", AppInit.rootPasswd)); string json = await Http.Get($"http://{AppInit.conf.listen.localhost}:{AppInit.conf.listen.port}/tmdb/api/3/{cat}/{id}?api_key={AppInit.conf.tmdb.api_key}&append_to_response=external_ids", timeoutSeconds: 5, headers: header); if (!string.IsNullOrWhiteSpace(json)) { imdb_id = Regex.Match(json, "\"imdb_id\":\"(tt[0-9]+)\"").Groups[1].Value; if (!string.IsNullOrEmpty(imdb_id)) { using (var sqlDb = ExternalidsContext.Factory != null ? ExternalidsContext.Factory.CreateDbContext() : new ExternalidsContext()) { sqlDb.Add(new ExternalidsSqlModel() { Id = $"{id}_{serial}", value = imdb_id }); await sqlDb.SaveChangesLocks(); } } } } } } } #endregion #region get kinopoisk_id string kpid = null; if (!string.IsNullOrWhiteSpace(imdb_id)) { externalids.TryGetValue(imdb_id, out kpid); if (string.IsNullOrEmpty(kpid) || kpid == "0") { using (var sqlDb = ExternalidsContext.Factory != null ? ExternalidsContext.Factory.CreateDbContext() : new ExternalidsContext()) { kpid = sqlDb.kinopoisk.Find(imdb_id)?.value; if (string.IsNullOrEmpty(kpid) && kinopoisk_id == 0) { string mkey = $"externalids:lockkpid:{imdb_id}"; if (!memoryCache.TryGetValue(mkey, out _)) { memoryCache.Set(mkey, 0, DateTime.Now.AddDays(1)); switch (AppInit.conf.online.findkp ?? "all") { case "alloha": kpid = await getAlloha(imdb_id); break; case "vsdn": kpid = await getVSDN(imdb_id); break; case "tabus": kpid = await getTabus(imdb_id); break; default: { var tasks = new List> { getVSDN(imdb_id), getAlloha(imdb_id), getTabus(imdb_id) }; while (tasks.Count > 0) { var completedTask = await Task.WhenAny(tasks); tasks.Remove(completedTask); var result = completedTask.Result; if (result != null) { kpid = result; break; } } break; } } if (!string.IsNullOrEmpty(kpid) && kpid != "0") { sqlDb.Add(new ExternalidsSqlModel() { Id = imdb_id, value = kpid }); await sqlDb.SaveChangesLocks(); } } } } } } #endregion kpid = kpid != null ? kpid : kinopoisk_id.ToString(); if (InvkEvent.IsExternalids()) InvkEvent.Externalids(id, ref imdb_id, ref kpid, serial); return Content($"{{\"imdb_id\":\"{imdb_id}\",\"kinopoisk_id\":\"{kpid}\"}}", "application/json; charset=utf-8"); } #endregion #region WithSearch [HttpGet] [AllowAnonymous] [Route("lite/withsearch")] public ActionResult WithSearch() { if (AppInit.conf.online.with_search == null) return ContentTo("[]"); return Json(AppInit.conf.online.with_search); } #endregion #region spider [HttpGet] [Route("lite/spider")] [Route("lite/spider/anime")] async public Task Spider(string title) { if (!AppInit.conf.online.spider) return ContentTo("{}"); var rch = new RchClient(HttpContext, host, new BaseSettings() { rhub = true }, requestInfo); if (rch.IsNotConnected() || rch.IsRequiredConnected()) return ContentTo(rch.connectionMsg); var user = requestInfo.user; var piders = new List<(string name, string uri, int index)>(); bool isanime = HttpContext.Request.Path.Value?.EndsWith("/anime") == true; #region module OnlineModuleEntry.EnsureCache(); var spiderArgs = new OnlineSpiderModel(title, isanime); if (OnlineModuleEntry.onlineModulesCache != null && OnlineModuleEntry.onlineModulesCache.Count > 0) { void addResult(List<(string name, string url, int index)> result) { if (result == null || result.Count == 0) return; foreach (var item in result) { if (string.IsNullOrEmpty(item.name) || string.IsNullOrEmpty(item.url)) continue; piders.Add((item.name, item.url, item.index)); } } foreach (var entry in OnlineModuleEntry.onlineModulesCache) { try { if (entry.Spider != null) { try { var result = entry.Spider(HttpContext, memoryCache, requestInfo, host, spiderArgs); addResult(result); } catch { } } if (entry.SpiderAsync != null) { try { var result = await entry.SpiderAsync(HttpContext, memoryCache, requestInfo, host, spiderArgs); addResult(result); } catch { } } } catch (Exception ex) { Console.WriteLine($"Modules {entry.mod?.NamespacePath(entry.mod.online)}: {ex.Message}\n\n"); } } } #endregion #region send void send(BaseSettings init, string plugin = null) { if (!init.spider || !init.enable || init.rip) return; if (init.geo_hide != null) { if (requestInfo.Country != null && init.geo_hide.Contains(requestInfo.Country)) return; } if (init.group_hide) { if (init.group > 0) { if (user == null || init.group > user.group) return; } else if (AppInit.conf.accsdb.enable) { if (user == null && string.IsNullOrEmpty(AppInit.conf.accsdb.premium_pattern)) return; } } string url = null; string displayname = init.displayname ?? init.plugin; if (string.IsNullOrEmpty(init.overridepasswd)) { url = init.overridehost; if (string.IsNullOrEmpty(url) && init.overridehosts != null && init.overridehosts.Length > 0) url = init.overridehosts[Random.Shared.Next(0, init.overridehosts.Length)]; } if (string.IsNullOrEmpty(url)) url = $"{host}/lite/" + (plugin ?? init.plugin).ToLower(); piders.Add((init.displayname ?? init.plugin, $"{url}?title={HttpUtility.UrlEncode(title)}&clarification=1&rjson=true&similar=true", init.displayindex)); } #endregion if (isanime) { send(AppInit.conf.Kodik); send(AppInit.conf.AnimeLib); send(AppInit.conf.AnilibriaOnline, "anilibria"); send(AppInit.conf.Animevost); send(AppInit.conf.Animebesst); send(AppInit.conf.MoonAnime); send(AppInit.conf.AnimeGo); } send(AppInit.conf.Filmix); send(AppInit.conf.FilmixTV, "filmixtv"); send(AppInit.conf.FilmixPartner, "fxapi"); send(AppInit.conf.Rezka); send(AppInit.conf.RezkaPrem, "rhsprem"); send(AppInit.conf.KinoPub); send(AppInit.conf.Kinogo); send(AppInit.conf.GetsTV, "getstv-search"); send(AppInit.conf.Kinobase); send(AppInit.conf.Alloha, "alloha-search"); send(AppInit.conf.Collaps, "collaps-search"); send(AppInit.conf.VeoVeo, "veoveo-spider"); if (!string.IsNullOrEmpty(AppInit.conf.VideoCDN.token)) send(AppInit.conf.VideoCDN); if (AppInit.conf.Lumex.priorityBrowser == "http" || PlaywrightBrowser.Status != PlaywrightStatus.disabled) send(AppInit.conf.Lumex); send(AppInit.conf.VDBmovies); send(AppInit.conf.HDVB, "hdvb-search"); return Json(piders.OrderByDescending(i => i.index).ToDictionary(k => k.name, v => v.uri)); } #endregion #region events [HttpGet] [AllowAnonymous] [Route("lifeevents")] public ActionResult LifeEvents(string memkey, long id, string imdb_id, long kinopoisk_id, int serial) { string json = null; JsonResult error(string msg) => Json(new { accsdb = true, ready = true, online = new string[] { }, msg }); List<(string code, int index, bool work)> _links = null; if (memoryCache.TryGetValue(memkey, out List<(string code, int index, bool work)> links)) _links = links.ToList(); if (_links != null && _links.Count(i => i.code != null) > 0) { bool ready = _links.Count == _links.Count(i => i.code != null); string online = string.Join(",", _links.Where(i => i.code != null).OrderByDescending(i => i.work).ThenBy(i => i.index).Select(i => i.code)); if (ready && !online.Contains("\"show\":true")) { if (string.IsNullOrEmpty(imdb_id) && 0 >= kinopoisk_id) return error($"Добавьте \"IMDB ID\" {(serial == 1 ? "сериала" : "фильма")} на https://themoviedb.org/{(serial == 1 ? "tv" : "movie")}/{id}/edit?active_nav_item=external_ids"); return error($"Не удалось найти онлайн для {(serial == 1 ? "сериала" : "фильма")}"); } json = "{" + $"\"ready\":{ready.ToString().ToLower()},\"tasks\":{_links.Count},\"online\":[{online.Replace("{localhost}", host)}]" + "}"; } return Content(json ?? "{\"ready\":false,\"tasks\":0,\"online\":[]}", contentType: "application/javascript; charset=utf-8"); } [HttpGet] [Route("lite/events")] async public ValueTask Events(string id, string imdb_id, long kinopoisk_id, long tmdb_id, string title, string original_title, string original_language, int year, string source, string rchtype, int serial = -1, bool life = false, bool islite = false, string account_email = null, string uid = null, string token = null, string nws_id = null) { var online = new List<(dynamic init, string name, string url, string plugin, int index)>(50); bool isanime = original_language is "ja" or "zh"; #region fix title bool fix_title = false; if (title != null && original_language != null && original_language.Split("|")[0] is "ja" or "ko" or "zh" or "cn") { if (long.TryParse(id, out long tmdbid) && tmdbid > 0) { Regex chineseRegex = new Regex("[\u4E00-\u9FFF]"); // Диапазон для китайских иероглифов Regex japaneseRegex = new Regex("[\u3040-\u30FF\uFF66-\uFF9F]"); // Хирагана, катакана и специальные символы Regex koreanRegex = new Regex("[\uAC00-\uD7AF]"); // Диапазон для корейских хангыльских символов if (chineseRegex.IsMatch(title) || japaneseRegex.IsMatch(title) || koreanRegex.IsMatch(title)) { var header = HeadersModel.Init(("localrequest", AppInit.rootPasswd)); var result = await Http.Get($"http://{AppInit.conf.listen.localhost}:{AppInit.conf.listen.port}/tmdb/api/3/{(serial == 1 ? "tv" : "movie")}/{tmdbid}?api_key={AppInit.conf.tmdb.api_key}&language=en", timeoutSeconds: 4, headers: header); if (result != null) { string _title = serial == 1 ? result.Value("name") : result.Value("title"); if (!string.IsNullOrEmpty(_title)) { title = _title; fix_title = true; } } } } } #endregion var conf = AppInit.conf; var user = requestInfo.user; JObject kitconf = await loadKitConf(); #region modules OnlineModuleEntry.EnsureCache(); if (OnlineModuleEntry.onlineModulesCache != null && OnlineModuleEntry.onlineModulesCache.Count > 0) { var args = new OnlineEventsModel(id, imdb_id, kinopoisk_id, title, original_title, original_language, year, source, rchtype, serial, life, islite, account_email, uid, token, nws_id, kitconf); foreach (var entry in OnlineModuleEntry.onlineModulesCache) { try { #region version >= 3 methods if (entry.Invoke != null) { try { var result = entry.Invoke(HttpContext, memoryCache, requestInfo, host, args); if (result != null && result.Count > 0) { foreach (var r in result) online.Add((null, r.name, r.url, r.plugin, r.index)); } } catch { } } if (entry.InvokeAsync != null) { try { var result = await entry.InvokeAsync(HttpContext, memoryCache, requestInfo, host, args); if (result != null && result.Count > 0) { foreach (var r in result) online.Add((null, r.name, r.url, r.plugin, r.index)); } } catch { } } #endregion #region version < 3 legacy methods if (entry.Events != null) { try { long.TryParse(id, out long tmdbid); var result = entry.Events(host, tmdbid, imdb_id, kinopoisk_id, title, original_title, original_language, year, source, serial, account_email); if (result != null && result.Count > 0) { foreach (var r in result) online.Add((null, r.name, r.url, r.plugin, r.index)); } } catch { } } if (entry.EventsAsync != null) { try { long.TryParse(id, out long tmdbid); var result = await entry.EventsAsync(HttpContext, memoryCache, host, tmdbid, imdb_id, kinopoisk_id, title, original_title, original_language, year, source, serial, account_email); if (result != null && result.Count > 0) { foreach (var r in result) online.Add((null, r.name, r.url, r.plugin, r.index)); } } catch { } } #endregion } catch (Exception ex) { Console.WriteLine($"Modules {entry.mod?.NamespacePath(entry.mod.online)}: {ex.Message}\n\n"); } } } #endregion #region send void send(BaseSettings _init, string plugin = null, string name = null, string arg_title = null, string arg_url = null, BaseSettings myinit = null) { var init = myinit != null ? _init : loadKit(_init, kitconf); bool enable = init.enable && !init.rip; if (!enable) return; if (rchtype != null) { if (init.client_type != null && !init.client_type.Contains(rchtype)) return; string rch_deny = init.RchAccessNotSupport(); if (rch_deny != null && rch_deny.Contains(rchtype)) return; string stream_deny = init.StreamAccessNotSupport(); if (stream_deny != null && stream_deny.Contains(rchtype)) return; if (init.rhub && !init.rhub_fallback && !init.corseu && string.IsNullOrWhiteSpace(init.webcorshost)) { if (init.rhub_geo_disable != null && requestInfo.Country != null && init.rhub_geo_disable.Contains(requestInfo.Country)) { return; } } } if (init.geo_hide != null && requestInfo.Country != null && init.geo_hide.Contains(requestInfo.Country)) { return; } if (init.group_hide) { if (init.group > 0) { if (user == null || init.group > user.group) return; } else if (AppInit.conf.accsdb.enable) { if (user == null && string.IsNullOrEmpty(AppInit.conf.accsdb.premium_pattern)) return; } } string url = string.Empty; if (string.IsNullOrEmpty(init.overridepasswd)) { url = init.overridehost; if (string.IsNullOrEmpty(url) && init.overridehosts != null && init.overridehosts.Length > 0) url = init.overridehosts[Random.Shared.Next(0, init.overridehosts.Length)]; } string displayname = init.displayname ?? name ?? init.plugin; if (!string.IsNullOrEmpty(url)) { if (plugin == "collaps-dash") { displayname = displayname.Replace("- 720p", "- 1080p"); url = url.Replace("/collaps", "/collaps-dash"); } } else { url = "{localhost}/lite/" + (plugin ?? (init.plugin ?? name).ToLower()) + arg_url; } if (original_language != null && original_language.Split("|")[0] is "ru" or "ja" or "ko" or "zh" or "cn") { string _p = (plugin ?? (init.plugin ?? name).ToLower()); if (_p is "filmix" or "filmixtv" or "fxapi" or "kinoukr" or "rezka" or "rhsprem" or "redheadsound" or "kinopub" or "alloha" or "lumex" or "vcdn" or "videocdn" or "fancdn" or "redheadsound" or "kinotochka" or "remux") // || (_p == "kodik" && kinopoisk_id == 0 && string.IsNullOrEmpty(imdb_id)) url += (url.Contains("?") ? "&" : "?") + "clarification=1"; } online.Add((myinit, $"{displayname}{arg_title}", url, (plugin ?? init.plugin ?? name).ToLower(), init.displayindex > 0 ? init.displayindex : online.Count)); } #endregion if (original_language != null && original_language.Split("|")[0] is "ja" or "ko" or "zh" or "cn" or "th" or "vi" or "tl") send(conf.Kodik); if (serial == -1 || isanime) { send(conf.AniLiberty); send(conf.AnilibriaOnline, "anilibria", "Anilibria"); send(conf.AnimeLib); send(conf.Animevost); send(conf.Animebesst); send(conf.AnimeGo); send(conf.AniMedia); send(conf.MoonAnime); } #region VoKino if (kinopoisk_id > 0 || source?.ToLower() == "vokino") { string vid = kinopoisk_id.ToString(); if (source?.ToLower() == "vokino" && !string.IsNullOrEmpty(id)) vid = id; var myinit = loadKit(conf.VoKino, kitconf , (j, i, c) => { if (j.ContainsKey("online")) i.online = c.online; return i; }); if (myinit.enable && !string.IsNullOrEmpty(myinit.token)) { async ValueTask vkino() { if (myinit.rhub || !conf.online.checkOnlineSearch) { VoKinoInvoke.SendOnline(myinit, online, null); } else { if (!hybridCache.TryGetValue($"vokino:view:{vid}", out JObject view)) { view = await Http.Get($"{myinit.corsHost()}/v2/view/{vid}?token={myinit.token}", timeoutSeconds: 4); if (view != null) hybridCache.Set($"vokino:view:{vid}", view, cacheTimeBase(20, init: conf.VoKino)); } if (view != null && view.ContainsKey("online") && view["online"] is JObject onlineObj) VoKinoInvoke.SendOnline(myinit, online, onlineObj); } }; if (AppInit.conf.accsdb.enable) { if (user != null) { if (myinit.group > user.group && myinit.group_hide) { } else await vkino(); } else { if (!string.IsNullOrEmpty(AppInit.conf.accsdb.premium_pattern)) await vkino(); } } else { if (myinit.group > 0 && myinit.group_hide && (user == null || myinit.group > user.group)) { } else await vkino(); } } } #endregion #region Filmix { var myinit = loadKit(conf.Filmix, kitconf, (j, i, c) => { if (j.ContainsKey("pro")) i.pro = c.pro; return i; }); if (string.IsNullOrEmpty(myinit.token) && (myinit.tokens == null || myinit.tokens.Length == 0) && conf.Filmix.hidefreeStart > 0) { if (TimeZoneTo.ByIds(["Europe/Kyiv", "Europe/Kiev", "FLE Standard Time"], out DateTime kievTime)) { if (kievTime.Hour >= conf.Filmix.hidefreeStart && kievTime.Hour < conf.Filmix.hidefreeEnd) myinit.enable = false; } } send(myinit, myinit: myinit); } send(conf.FilmixTV, "filmixtv"); send(conf.FilmixPartner, "fxapi", "Filmix"); #endregion send(conf.KinoPub); send(conf.IptvOnline, "iptvonline", "iptv.online"); send(conf.GetsTV); #region Alloha { var myinit = loadKit(conf.Alloha, kitconf , (j, i, c) => { if (j.ContainsKey("m4s")) i.m4s = c.m4s; return i; }); send(myinit, myinit: myinit); } #endregion #region Rezka { var rezka_premium = loadKit(conf.RezkaPrem, kitconf , (j, i, c) => { if (j.ContainsKey("premium")) i.premium = c.premium; return i; }); send(rezka_premium, "rhsprem", "HDRezka", myinit: rezka_premium); if (rezka_premium.enable == false) { var myinit = await loadKit(conf.Rezka, (j, i, c) => { if (j.ContainsKey("premium")) i.premium = c.premium; return i; }); send(myinit, myinit: myinit); } } #endregion if (PlaywrightBrowser.Status != PlaywrightStatus.disabled) send(conf.Mirage); if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Kinobase.overridehost) || conf.Kinobase.overridehosts?.Length > 0) send(conf.Kinobase); if (conf.VDBmovies.rhub || conf.VDBmovies.priorityBrowser == "http" || PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.VDBmovies.overridehost) || conf.VDBmovies.overridehosts?.Length > 0) send(conf.VDBmovies); if (kinopoisk_id > 0) { if (conf.VideoDB.rhub || conf.VideoDB.priorityBrowser == "http" || PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.VideoDB.overridehost) || conf.VideoDB.overridehosts?.Length > 0) send(conf.VideoDB); if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Zetflix.overridehost) || conf.Zetflix.overridehosts?.Length > 0) send(conf.Zetflix); } if ((serial == -1 || serial == 0) && kinopoisk_id > 0) send(conf.FanCDN); send(conf.VideoCDN); if (conf.Lumex.priorityBrowser == "http" || PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Lumex.overridehost) || conf.Lumex.overridehosts?.Length > 0) send(conf.Lumex); if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Kinogo.overridehost) || conf.Kinogo.overridehosts?.Length > 0) send(conf.Kinogo); if (kinopoisk_id > 0) send(conf.Ashdi, "ashdi", "Ashdi (Украинский)"); if (!isanime) send(conf.Kinoukr, "kinoukr", "Kinoukr (Украинский)"); send(conf.Eneyida, "eneyida", "Eneyida (Украинский)"); #region Collaps { var myinit = loadKit(conf.Collaps, kitconf, (j, i, c) => { if (j.ContainsKey("dash")) i.dash = c.dash; if (j.ContainsKey("two")) i.two = c.two; return i; }); send(myinit, "collaps", $"Collaps ({(myinit.dash ? "DASH" : "HLS")})", myinit: myinit); if (myinit.two && !myinit.dash) send(myinit, "collaps-dash", "Collaps (DASH)"); } #endregion if (serial == -1 || serial == 0) { send(conf.Plvideo, "plvideo", "Plvideo"); send(conf.RutubeMovie, "rutubemovie", "Rutube"); send(conf.VkMovie, "vkmovie", "VK Видео"); } if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Videoseed.overridehost) || conf.Videoseed.overridehosts?.Length > 0) send(conf.Videoseed); send(conf.Vibix); send(conf.VeoVeo); if (serial == -1 || serial == 0) send(conf.iRemux, "remux"); #region PidTor if (conf.PidTor.enable) { if ((conf.PidTor.torrs != null && conf.PidTor.torrs.Length > 0) || (conf.PidTor.auth_torrs != null && conf.PidTor.auth_torrs.Count > 0) || AppInit.modules.FirstOrDefault(i => i.dll == "TorrServer.dll" && i.enable) != null) { void psend() { var _conf = InvkEvent.conf.PidTor != null ? conf.PidTor.Clone() : conf.PidTor; InvkEvent.PidTor(new EventPidTor(_conf, requestInfo, hybridCache)); if (!_conf.enable) return; if (_conf.group > 0 && _conf.group_hide) { if (user == null || _conf.group > user.group) return; } online.Add((null, $"{_conf.displayname ?? "PidŦor"}", "{localhost}/lite/pidtor", "pidtor", _conf.displayindex > 0 ? _conf.displayindex : online.Count)); } psend(); } } #endregion if (serial == -1 || serial == 0) send(conf.Redheadsound); send(conf.HDVB); send(conf.Kinotochka); if ((serial == -1 || (serial == 1 && !isanime)) && kinopoisk_id > 0) send(conf.CDNmovies); if (serial == -1 || serial == 0) send(conf.IframeVideo); if (kinopoisk_id > 0 && !isanime) send(conf.CDNvideohub, "cdnvideohub", "VideoHUB"); #region ENG if ((original_language == null || original_language == "en") && conf.disableEng == false) { if (tmdb_id > 0 || (source != null && (source is "tmdb" or "cub"))) { if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Hydraflix.overridehost) || conf.Hydraflix.overridehosts?.Length > 0) send(conf.Hydraflix, "hydraflix", "HydraFlix (ENG)"); if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Vidsrc.overridehost) || conf.Vidsrc.overridehosts?.Length > 0) send(conf.Vidsrc, "vidsrc", "VidSrc (ENG)"); if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.VidLink.overridehost) || conf.VidLink.overridehosts?.Length > 0) send(conf.VidLink, "vidlink", "VidLink (ENG)"); if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Videasy.overridehost) || conf.Videasy.overridehosts?.Length > 0) send(conf.Videasy, "videasy", "Videasy (ENG)"); if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.MovPI.overridehost) || conf.MovPI.overridehosts?.Length > 0) send(conf.MovPI, "movpi", "MovPI (ENG)"); if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Smashystream.overridehost) || conf.Smashystream.overridehosts?.Length > 0) send(conf.Smashystream, "smashystream", "SmashyStream (ENG)"); if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Autoembed.overridehost) || conf.Autoembed.overridehosts?.Length > 0) send(conf.Autoembed, "autoembed", "AutoEmbed (ENG)"); if (PlaywrightBrowser.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Playembed.overridehost) || conf.Playembed.overridehosts?.Length > 0) send(conf.Playembed, "playembed", "PlayEmbed (ENG)"); if (Firefox.Status != PlaywrightStatus.disabled || !string.IsNullOrEmpty(conf.Twoembed.overridehost) || conf.Twoembed.overridehosts?.Length > 0) send(conf.Twoembed, "twoembed", "2Embed (ENG)"); send(conf.Rgshows, "rgshows", "RgShows (ENG)"); } } #endregion if (!life && conf.litejac) online.Add((null, "Торренты", "{localhost}/lite/jac", "jac", 200)); #region checkOnlineSearch bool chos = conf.online.checkOnlineSearch && !string.IsNullOrEmpty(id); if (chos && IO.File.Exists("isdocker")) { string version = await Http.Get($"http://{AppInit.conf.listen.localhost}:{AppInit.conf.listen.port}/version", timeoutSeconds: 4, headers: HeadersModel.Init("localrequest", AppInit.rootPasswd)); if (version == null || !version.StartsWith(appversion)) chos = false; } if (chos) { string memkey = CrypTo.md5($"checkOnlineSearch:{id}:{serial}:{source?.Replace("tmdb", "")?.Replace("cub", "")}:{online.Count}:{(IsKitConf ? requestInfo.user_uid : null)}"); if (!memoryCache.TryGetValue(memkey, out List<(string code, int index, bool work)> links) || !conf.multiaccess) { var tasks = new List(); links = new List<(string code, int index, bool work)>(online.Count); for (int i = 0; i < online.Count; i++) links.Add(default); memoryCache.Set(memkey, links, DateTime.Now.AddMinutes(5)); foreach (var o in online) { var tk = checkSearch(memkey, links, tasks.Count, o.init, o.index, o.name, o.url, o.plugin, id, imdb_id, kinopoisk_id, tmdb_id, title, original_title, original_language, source, year, serial, life, rchtype); tasks.Add(tk); } if (life) return Json(new { life = true, memkey, title = (fix_title ? title : null) }); await Task.WhenAll(tasks); } if (life) return Json(new { life = true, memkey }); return ContentTo($"[{string.Join(",", links.Where(i => i.code != null).OrderByDescending(i => i.work).ThenBy(i => i.index).Select(i => i.code)).Replace("{localhost}", host)}]"); } #endregion string online_result = string.Join(",", online.OrderBy(i => i.index).Select(i => "{\"name\":\"" + i.name + "\",\"url\":\"" + i.url + "\",\"balanser\":\"" + i.plugin + "\"}")); return ContentTo($"[{online_result.Replace("{localhost}", host)}]"); } #endregion #region checkSearch async Task checkSearch(string memkey, List<(string code, int index, bool work)> links, int indexList, dynamic init, int index, string name, string uri, string plugin, string id, string imdb_id, long kinopoisk_id, long tmdb_id, string title, string original_title, string original_language, string source, int year, int serial, bool life, string rchtype) { try { string srq = uri.Replace("{localhost}", $"http://{AppInit.conf.listen.localhost}:{AppInit.conf.listen.port}"); var header = uri.Contains("{localhost}") ? HeadersModel.Init(("xhost", host), ("xscheme", HttpContext.Request.Scheme), ("localrequest", AppInit.rootPasswd)) : null; string checkuri = $"{srq}{(srq.Contains("?") ? "&" : "?")}id={HttpUtility.UrlEncode(id)}&imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&tmdb_id={tmdb_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&original_language={original_language}&source={source}&year={year}&serial={serial}&rchtype={rchtype}&checksearch=true"; string res = await Http.Get(AccsDbInvk.Args(checkuri, HttpContext), timeoutSeconds: 10, headers: header); if (string.IsNullOrEmpty(res)) res = string.Empty; bool rch = res.Contains("\"rch\":true"); bool work = rch || res.Contains("data-json=") || res.Contains("\"type\":\"movie\"") || res.Contains("\"type\":\"episode\"") || res.Contains("\"type\":\"season\""); string quality = string.Empty; string balanser = plugin.Contains("/") ? plugin.Split("/")[1] : plugin; #region определение качества if (work && life) { foreach (string q in new string[] { "2160", "1080", "720", "480", "360" }) { if (res.Contains("").Groups[1].Value; break; } else if (res.Contains($"\"{q}p\"") || res.Contains($">{q}p<") || res.Contains($"")) { quality = $" - {q}p"; break; } } if (quality == "2160") quality = res.Contains("HDR") ? " - 4K HDR" : " - 4K"; if (init != null) { if (balanser == "filmix") { if (!init.pro) quality = string.IsNullOrEmpty(init.token) ? " - 480p" : " - 720p"; } if (balanser == "alloha") quality = string.IsNullOrEmpty(quality) ? (init.m4s ? " ~ 2160p" : " ~ 1080p") : quality; if (balanser == "rezka" || balanser == "rhs") { string rezkaq = init.premium ? " ~ 2160p" : " ~ 720p"; quality = string.IsNullOrEmpty(quality) ? rezkaq : quality; } if (balanser == "collaps") quality = init.dash ? " ~ 1080p" : " ~ 720p"; } if (quality == string.Empty) { switch (balanser) { case "fxapi": case "filmix": case "filmixtv": case "kinopub": case "vokino": case "vokino-alloha": case "vokino-filmix": case "alloha": case "remux": case "pidtor": case "rhsprem": case "animelib": case "mirage": case "videodb": case "iptvonline": case "plvideo": case "rutubemovie": case "vkmovie": quality = " ~ 2160p"; break; case "kinobase": case "kinogo": case "getstv": case "zetflix": case "vcdn": case "videocdn": case "lumex": case "vibix": case "videoseed": case "eneyida": case "kinoukr": case "ashdi": case "hdvb": case "anilibria": case "aniliberty": case "redheadsound": case "iframevideo": case "animego": case "lostfilmhd": case "vdbmovies": case "collaps-dash": case "fancdn": case "cdnvideohub": case "moonanime": case "playembed": case "rgshows": case "twoembed": case "vidsrc": case "smashystream": case "hydraflix": case "movpi": case "videasy": case "vidlink": case "autoembed": case "veoveo": case "vokino-vibix": case "vokino-monframe": case "vokino-remux": case "vokino-ashdi": case "vokino-hdvb": quality = " ~ 1080p"; break; case "voidboost": case "animedia": case "animevost": case "animebesst": case "kodik": case "kinotochka": case "rhs": quality = " ~ 720p"; break; case "kinokrad": case "kinoprofi": case "seasonvar": quality = " - 480p"; break; case "cdnmovies": quality = " - 360p"; break; default: break; } if (balanser == "vokino") quality = res.Contains("4K HDR") ? " - 4K HDR" : res.Contains("4K ") ? " - 4K" : quality; } } #endregion if (!name.Contains(" - ") && AppInit.conf.online.showquality && !string.IsNullOrEmpty(quality)) { name = Regex.Replace(name, " ~ .*$", ""); name += quality; } links[indexList] = ("{" + $"\"name\":\"{name}\",\"url\":\"{uri}\",\"index\":{index},\"show\":{work.ToString().ToLower()},\"balanser\":\"{plugin}\",\"rch\":{rch.ToString().ToLower()}" + "}", index, work); } catch (Exception ex) { Console.WriteLine("checkSearch: " + ex.ToString()); } } #endregion } }