From 6aece92fd0bb83429a647de7717ea04990e81928 Mon Sep 17 00:00:00 2001 From: Felix Date: Sat, 28 Mar 2026 10:18:21 +0200 Subject: [PATCH] refactor!: migrate all modules to new module interface architecture BREAKING CHANGE: All module routes changed from /{module} to /lite/{module} - Implement IModuleLoaded and IModuleOnline interfaces across all modules - Add HttpHydra support to all Invoke classes for HTTP request handling - Replace ModuleInvoke.Conf() with ModuleInvoke.Init() in all ModInit classes - Convert loadKit() from async to synchronous calls in all controllers - Replace direct AppInit.conf.online.with_search.Add() with reflection-based RegisterWithSearch() method for decoupled module registration - Simplify cacheTime() logic by removing mikrotik/multiaccess conditionals - Add GlobalUsings.cs to all modules for shared namespace imports - Update OnlineApi to use ModuleOnlineItem instead of value tuples - Bump all module versions to new major versions --- AnimeON/AnimeON.csproj | 2 +- AnimeON/AnimeONInvoke.cs | 27 +++++--- AnimeON/Controller.cs | 87 +++++++++++++++++-------- AnimeON/GlobalUsings.cs | 4 ++ AnimeON/ModInit.cs | 49 ++++++++++++-- AnimeON/OnlineApi.cs | 41 ++++++------ Bamboo/Bamboo.csproj | 2 +- Bamboo/BambooInvoke.cs | 20 ++++-- Bamboo/Controller.cs | 57 +++++++++++++---- Bamboo/GlobalUsings.cs | 4 ++ Bamboo/ModInit.cs | 49 ++++++++++++-- Bamboo/OnlineApi.cs | 29 +++++---- JackTor/Controller.cs | 106 ++++++++++++++++++++----------- JackTor/GlobalUsings.cs | 4 ++ JackTor/JackTor.csproj | 2 +- JackTor/JackTorInvoke.cs | 1 - JackTor/ModInit.cs | 50 +++++++++++++-- JackTor/Models/JackTorModels.cs | 14 ++++ JackTor/OnlineApi.cs | 39 +++++------- KlonFUN/Controller.cs | 65 ++++++++++++++----- KlonFUN/GlobalUsings.cs | 4 ++ KlonFUN/KlonFUN.csproj | 2 +- KlonFUN/KlonFUNInvoke.cs | 32 +++++++--- KlonFUN/ModInit.cs | 49 ++++++++++++-- KlonFUN/OnlineApi.cs | 29 +++++---- Makhno/Controller.cs | 59 +++++++++++++---- Makhno/GlobalUsings.cs | 4 ++ Makhno/Makhno.csproj | 2 +- Makhno/MakhnoInvoke.cs | 16 ++++- Makhno/ModInit.cs | 49 ++++++++++++-- Makhno/OnlineApi.cs | 29 +++++---- Mikai/Controller.cs | 81 ++++++++++++++++------- Mikai/GlobalUsings.cs | 4 ++ Mikai/Mikai.csproj | 2 +- Mikai/MikaiInvoke.cs | 22 +++++-- Mikai/ModInit.cs | 49 ++++++++++++-- Mikai/OnlineApi.cs | 35 +++++----- NMoonAnime/Controller.cs | 81 ++++++++++++++++------- NMoonAnime/GlobalUsings.cs | 4 ++ NMoonAnime/ModInit.cs | 49 ++++++++++++-- NMoonAnime/NMoonAnime.csproj | 2 +- NMoonAnime/NMoonAnimeInvoke.cs | 18 ++++-- NMoonAnime/OnlineApi.cs | 29 +++++---- StarLight/Controller.cs | 73 +++++++++++++++------ StarLight/GlobalUsings.cs | 4 ++ StarLight/ModInit.cs | 49 ++++++++++++-- StarLight/OnlineApi.cs | 29 +++++---- StarLight/StarLight.csproj | 2 +- StarLight/StarLightInvoke.cs | 22 +++++-- Uaflix/Controller.cs | 85 +++++++++++++++++-------- Uaflix/GlobalUsings.cs | 4 ++ Uaflix/ModInit.cs | 49 ++++++++++++-- Uaflix/OnlineApi.cs | 39 +++++++----- Uaflix/Uaflix.csproj | 2 +- Uaflix/UaflixInvoke.cs | 33 ++++++++-- Unimay/Controllers/Controller.cs | 44 +++++++++++-- Unimay/GlobalUsings.cs | 4 ++ Unimay/ModInit.cs | 72 ++++++++++++++------- Unimay/OnlineApi.cs | 35 +++++----- Unimay/Unimay.csproj | 12 ++-- Unimay/UnimayInvoke.cs | 27 +++++--- 61 files changed, 1386 insertions(+), 502 deletions(-) create mode 100644 AnimeON/GlobalUsings.cs create mode 100644 Bamboo/GlobalUsings.cs create mode 100644 JackTor/GlobalUsings.cs create mode 100644 KlonFUN/GlobalUsings.cs create mode 100644 Makhno/GlobalUsings.cs create mode 100644 Mikai/GlobalUsings.cs create mode 100644 NMoonAnime/GlobalUsings.cs create mode 100644 StarLight/GlobalUsings.cs create mode 100644 Uaflix/GlobalUsings.cs create mode 100644 Unimay/GlobalUsings.cs diff --git a/AnimeON/AnimeON.csproj b/AnimeON/AnimeON.csproj index c26a806..9512ffc 100644 --- a/AnimeON/AnimeON.csproj +++ b/AnimeON/AnimeON.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 library true diff --git a/AnimeON/AnimeONInvoke.cs b/AnimeON/AnimeONInvoke.cs index 51cec51..7abb034 100644 --- a/AnimeON/AnimeONInvoke.cs +++ b/AnimeON/AnimeONInvoke.cs @@ -23,13 +23,15 @@ namespace AnimeON private IHybridCache _hybridCache; private Action _onLog; private ProxyManager _proxyManager; + private readonly HttpHydra _httpHydra; - public AnimeONInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager) + public AnimeONInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager, HttpHydra httpHydra = null) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; + _httpHydra = httpHydra; } string AshdiRequestUrl(string url) @@ -61,7 +63,7 @@ namespace AnimeON string searchUrl = $"{_init.host}/api/anime/search?text={System.Web.HttpUtility.UrlEncode(query)}"; _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {searchUrl}"); - string searchJson = await Http.Get(_init.cors(searchUrl), headers: headers, proxy: _proxyManager.Get()); + string searchJson = await HttpGet(searchUrl, headers); if (string.IsNullOrEmpty(searchJson)) return null; @@ -124,7 +126,7 @@ namespace AnimeON string fundubsUrl = $"{_init.host}/api/player/{animeId}/translations"; _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {fundubsUrl}"); - string fundubsJson = await Http.Get(_init.cors(fundubsUrl), headers: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get()); + string fundubsJson = await HttpGet(fundubsUrl, new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }); if (string.IsNullOrEmpty(fundubsJson)) return null; @@ -150,7 +152,7 @@ namespace AnimeON string episodesUrl = $"{_init.host}/api/player/{animeId}/episodes?take=100&skip=-1&playerId={playerId}&translationId={fundubId}"; _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {episodesUrl}"); - string episodesJson = await Http.Get(_init.cors(episodesUrl), headers: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get()); + string episodesJson = await HttpGet(episodesUrl, new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }); if (string.IsNullOrEmpty(episodesJson)) return null; @@ -169,7 +171,7 @@ namespace AnimeON }; _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {requestUrl}"); - string html = await Http.Get(_init.cors(requestUrl), headers: headers, proxy: _proxyManager.Get()); + string html = await HttpGet(requestUrl, headers); if (string.IsNullOrEmpty(html)) return null; @@ -206,7 +208,7 @@ namespace AnimeON string requestUrl = AshdiRequestUrl(WithAshdiMultivoice(url, enable: !disableAshdiMultivoiceForVod)); _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {requestUrl}"); - string html = await Http.Get(_init.cors(requestUrl), headers: headers, proxy: _proxyManager.Get()); + string html = await HttpGet(requestUrl, headers); if (string.IsNullOrEmpty(html)) return streams; @@ -263,7 +265,7 @@ namespace AnimeON string url = $"{_init.host}/api/player/{episodeId}/episode"; _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}"); - string json = await Http.Get(_init.cors(url), headers: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get()); + string json = await HttpGet(url, new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }); if (string.IsNullOrEmpty(json)) return null; @@ -474,12 +476,21 @@ namespace AnimeON if (init != null && init.rhub && rhub != -1) return TimeSpan.FromMinutes(rhub); - int ctime = AppInit.conf.mikrotik ? mikrotik : AppInit.conf.multiaccess ? init != null && init.cache_time > 0 ? init.cache_time : multiaccess : home; + int ctime = init != null && init.cache_time > 0 ? init.cache_time : multiaccess; if (ctime > multiaccess) ctime = multiaccess; return TimeSpan.FromMinutes(ctime); } + + private Task HttpGet(string url, List headers) + { + if (_httpHydra != null) + return _httpHydra.Get(url, newheaders: headers); + + return Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get()); + } + public async Task AggregateSerialStructure(int animeId, int season) { string memKey = $"AnimeON:aggregated:{animeId}:{season}"; diff --git a/AnimeON/Controller.cs b/AnimeON/Controller.cs index a3a1216..f5024fa 100644 --- a/AnimeON/Controller.cs +++ b/AnimeON/Controller.cs @@ -27,27 +27,27 @@ namespace AnimeON.Controllers } [HttpGet] - [Route("animeon")] + [Route("lite/animeon")] async public Task Index(long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email, string t, int s = -1, bool rjson = false, bool checksearch = false) { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.AnimeON); + var init = loadKit(ModInit.AnimeON); if (!init.enable) return Forbid(); - var invoke = new AnimeONInvoke(init, hybridCache, OnLog, proxyManager); + var invoke = new AnimeONInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); if (checksearch) { - if (AppInit.conf?.online?.checkOnlineSearch != true) - return OnError("animeon", proxyManager); + if (!IsCheckOnlineSearchEnabled()) + return OnError("animeon", refresh_proxy: true); var checkSeasons = await invoke.Search(imdb_id, kinopoisk_id, title, original_title, year, serial); if (checkSeasons != null && checkSeasons.Count > 0) return Content("data-json=", "text/plain; charset=utf-8"); - return OnError("animeon", proxyManager); + return OnError("animeon", refresh_proxy: true); } OnLog($"AnimeON Index: title={title}, original_title={original_title}, serial={serial}, s={s}, t={t}, year={year}, imdb_id={imdb_id}, kp={kinopoisk_id}"); @@ -55,7 +55,7 @@ namespace AnimeON.Controllers var seasons = await invoke.Search(imdb_id, kinopoisk_id, title, original_title, year, serial); OnLog($"AnimeON: search results = {seasons?.Count ?? 0}"); if (seasons == null || seasons.Count == 0) - return OnError("animeon", proxyManager); + return OnError("animeon", refresh_proxy: true); // [Refactoring] Використовується агрегована структура (AggregateSerialStructure) — попередній збір allOptions не потрібний @@ -81,7 +81,7 @@ namespace AnimeON.Controllers foreach (var item in seasonItems) { string seasonName = item.SeasonNumber.ToString(); - string link = $"{host}/animeon?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={item.SeasonNumber}"; + string link = $"{host}/lite/animeon?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={item.SeasonNumber}"; season_tpl.Append(seasonName, link, seasonName); } OnLog($"AnimeON: return seasons count={seasonItems.Count}"); @@ -106,13 +106,13 @@ namespace AnimeON.Controllers selected = new { Anime = seasons[s], Index = s, SeasonNumber = seasons[s].Season > 0 ? seasons[s].Season : s + 1 }; if (selected == null) - return OnError("animeon", proxyManager); + return OnError("animeon", refresh_proxy: true); var selectedAnime = selected.Anime; int selectedSeasonNumber = selected.SeasonNumber; var structure = await invoke.AggregateSerialStructure(selectedAnime.Id, selectedSeasonNumber); if (structure == null || !structure.Voices.Any()) - return OnError("animeon", proxyManager); + return OnError("animeon", refresh_proxy: true); OnLog($"AnimeON: voices found = {structure.Voices.Count}"); var voiceItems = structure.Voices @@ -135,14 +135,14 @@ namespace AnimeON.Controllers var voice_tpl = new VoiceTpl(); foreach (var voice in voiceItems) { - string voiceLink = $"{host}/animeon?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={s}&t={HttpUtility.UrlEncode(voice.Key)}"; + string voiceLink = $"{host}/lite/animeon?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={s}&t={HttpUtility.UrlEncode(voice.Key)}"; bool isActive = voice.Key == t; voice_tpl.Append(voice.Display, isActive, voiceLink); } // Перевірка вибраної озвучки if (!structure.Voices.ContainsKey(t)) - return OnError("animeon", proxyManager); + return OnError("animeon", refresh_proxy: true); var episode_tpl = new EpisodeTpl(); var selectedVoiceInfo = structure.Voices[t]; @@ -179,7 +179,7 @@ namespace AnimeON.Controllers if (string.IsNullOrEmpty(streamLink) && ep.EpisodeId > 0) { - string callUrl = $"{host}/animeon/play?episode_id={ep.EpisodeId}&serial=1"; + string callUrl = $"{host}/lite/animeon/play?episode_id={ep.EpisodeId}&serial=1"; episode_tpl.Append(episodeName, title ?? original_title, seasonStr, episodeStr, accsArgs(callUrl), "call"); continue; } @@ -189,7 +189,7 @@ namespace AnimeON.Controllers if (needsResolve || streamLink.Contains("moonanime.art") || streamLink.Contains("ashdi.vip/vod")) { - string callUrl = $"{host}/animeon/play?url={HttpUtility.UrlEncode(streamLink)}&serial=1"; + string callUrl = $"{host}/lite/animeon/play?url={HttpUtility.UrlEncode(streamLink)}&serial=1"; episode_tpl.Append(episodeName, title ?? original_title, seasonStr, episodeStr, accsArgs(callUrl), "call"); } else @@ -212,12 +212,12 @@ namespace AnimeON.Controllers { var firstAnime = seasons.FirstOrDefault(); if (firstAnime == null) - return OnError("animeon", proxyManager); + return OnError("animeon", refresh_proxy: true); var fundubs = await invoke.GetFundubs(firstAnime.Id); OnLog($"AnimeON: movie fundubs count = {fundubs?.Count ?? 0}"); if (fundubs == null || fundubs.Count == 0) - return OnError("animeon", proxyManager); + return OnError("animeon", refresh_proxy: true); var tpl = new MovieTpl(title, original_title); @@ -251,7 +251,7 @@ namespace AnimeON.Controllers foreach (var ashdiStream in ashdiStreams) { string optionName = $"{translationName} {ashdiStream.title}"; - string callUrl = $"{host}/animeon/play?url={HttpUtility.UrlEncode(ashdiStream.link)}"; + string callUrl = $"{host}/lite/animeon/play?url={HttpUtility.UrlEncode(ashdiStream.link)}"; tpl.Append(optionName, accsArgs(callUrl), "call"); } continue; @@ -260,7 +260,7 @@ namespace AnimeON.Controllers if (needsResolve || streamLink.Contains("moonanime.art/iframe/") || streamLink.Contains("ashdi.vip/vod")) { - string callUrl = $"{host}/animeon/play?url={HttpUtility.UrlEncode(streamLink)}"; + string callUrl = $"{host}/lite/animeon/play?url={HttpUtility.UrlEncode(streamLink)}"; tpl.Append(translationName, accsArgs(callUrl), "call"); } else @@ -272,7 +272,7 @@ namespace AnimeON.Controllers // Якщо не зібрали жодної опції — повертаємо помилку if (tpl.data == null || tpl.data.Count == 0) - return OnError("animeon", proxyManager); + return OnError("animeon", refresh_proxy: true); OnLog("AnimeON: return movie options"); return rjson ? Content(tpl.ToJson(), "application/json; charset=utf-8") : Content(tpl.ToHtml(), "text/html; charset=utf-8"); @@ -283,7 +283,7 @@ namespace AnimeON.Controllers { string fundubsUrl = $"{init.host}/api/player/{animeId}/translations"; - string fundubsJson = await Http.Get(init.cors(fundubsUrl), headers: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) }); + string fundubsJson = await httpHydra.Get(fundubsUrl, newheaders: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) }); if (string.IsNullOrEmpty(fundubsJson)) return null; @@ -308,7 +308,7 @@ namespace AnimeON.Controllers { string episodesUrl = $"{init.host}/api/player/{animeId}/episodes?take=100&skip=-1&playerId={playerId}&translationId={fundubId}"; - string episodesJson = await Http.Get(init.cors(episodesUrl), headers: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) }); + string episodesJson = await httpHydra.Get(episodesUrl, newheaders: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) }); if (string.IsNullOrEmpty(episodesJson)) return null; @@ -332,7 +332,7 @@ namespace AnimeON.Controllers string searchUrl = $"{init.host}/api/anime/search?text={HttpUtility.UrlEncode(query)}"; - string searchJson = await Http.Get(init.cors(searchUrl), headers: headers); + string searchJson = await httpHydra.Get(searchUrl, newheaders: headers); if (string.IsNullOrEmpty(searchJson)) return null; @@ -373,16 +373,16 @@ namespace AnimeON.Controllers return null; } - [HttpGet("animeon/play")] + [HttpGet("lite/animeon/play")] public async Task Play(string url, int episode_id = 0, string title = null, int serial = 0) { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.AnimeON); + var init = loadKit(ModInit.AnimeON); if (!init.enable) return Forbid(); - var invoke = new AnimeONInvoke(init, hybridCache, OnLog, proxyManager); + var invoke = new AnimeONInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); bool disableAshdiMultivoiceForVod = serial == 1; OnLog($"AnimeON Play: url={url}, episode_id={episode_id}, serial={serial}"); @@ -398,13 +398,13 @@ namespace AnimeON.Controllers else { OnLog("AnimeON Play: empty url"); - return OnError("animeon", proxyManager); + return OnError("animeon", refresh_proxy: true); } if (string.IsNullOrEmpty(streamLink)) { OnLog("AnimeON Play: cannot extract stream"); - return OnError("animeon", proxyManager); + return OnError("animeon", refresh_proxy: true); } List streamHeaders = null; @@ -462,5 +462,38 @@ namespace AnimeON.Controllers return HostStreamProxy(init, link, headers: headers, force_streamproxy: forceProxy); } + + private static bool IsCheckOnlineSearchEnabled() + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var checkProp = conf?.GetType().GetProperty("checkOnlineSearch", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (checkProp?.GetValue(conf) is bool enabled) + return enabled; + } + catch + { + } + + return true; + } + + private static void OnLog(string message) + { + System.Console.WriteLine(message); + } } } diff --git a/AnimeON/GlobalUsings.cs b/AnimeON/GlobalUsings.cs new file mode 100644 index 0000000..4c00409 --- /dev/null +++ b/AnimeON/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Shared.Services; +global using Shared.Services.Hybrid; +global using Shared.Models.Base; +global using AppInit = Shared.CoreInit; diff --git a/AnimeON/ModInit.cs b/AnimeON/ModInit.cs index 316d204..872f735 100644 --- a/AnimeON/ModInit.cs +++ b/AnimeON/ModInit.cs @@ -3,6 +3,7 @@ using Newtonsoft.Json.Linq; using Shared; using Shared.Engine; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using Shared.Models.Online.Settings; using Microsoft.AspNetCore.Mvc; using Microsoft.CodeAnalysis.Scripting; @@ -23,9 +24,9 @@ using System.Threading.Tasks; namespace AnimeON { - public class ModInit + public class ModInit : IModuleLoaded { - public static double Version => 3.7; + public static double Version => 4.0; public static OnlinesSettings AnimeON; public static bool ApnHostProvided; @@ -39,7 +40,7 @@ namespace AnimeON /// /// модуль загружен /// - public static void loaded(InitspaceModel initspace) + public void Loaded(InitspaceModel initspace) { @@ -55,7 +56,7 @@ namespace AnimeON list = new string[] { "socks5://ip:port" } } }; - var conf = ModuleInvoke.Conf("AnimeON", AnimeON); + var conf = ModuleInvoke.Init("AnimeON", JObject.FromObject(AnimeON)); bool hasApn = ApnHelper.TryGetInitConf(conf, out bool apnEnabled, out string apnHost); conf.Remove("apn"); conf.Remove("apn_host"); @@ -74,7 +75,45 @@ namespace AnimeON } // Виводити "уточнити пошук" - AppInit.conf.online.with_search.Add("animeon"); + RegisterWithSearch("animeon"); + } + + private static void RegisterWithSearch(string plugin) + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var withSearchProp = conf?.GetType().GetProperty("with_search", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (withSearchProp?.GetValue(conf) is System.Collections.IList list) + { + foreach (var item in list) + { + if (string.Equals(item?.ToString(), plugin, StringComparison.OrdinalIgnoreCase)) + return; + } + + list.Add(plugin); + } + } + catch + { + } + } + + public void Dispose() + { } } diff --git a/AnimeON/OnlineApi.cs b/AnimeON/OnlineApi.cs index 2664bda..c143c44 100644 --- a/AnimeON/OnlineApi.cs +++ b/AnimeON/OnlineApi.cs @@ -1,47 +1,46 @@ -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Shared.Models; -using Shared.Models.Base; using Shared.Models.Module; -using System.Collections.Generic; - +using Shared.Models.Module.Interfaces; +using System.Collections.Generic; +using System.Threading.Tasks; + namespace AnimeON { - public class OnlineApi + public class OnlineApi : IModuleOnline { - public static List<(string name, string url, string plugin, int index)> Invoke( - HttpContext httpContext, - IMemoryCache memoryCache, - RequestModel requestInfo, - string host, - OnlineEventsModel args) + public List Invoke(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) { long.TryParse(args.id, out long tmdbid); return Events(host, tmdbid, args.imdb_id, args.kinopoisk_id, args.title, args.original_title, args.original_language, args.year, args.source, args.serial, args.account_email); } - public static List<(string name, string url, string plugin, int index)> Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) + public Task> InvokeAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) + => Task.FromResult(default(List)); + + public List Spider(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => null; + + public Task> SpiderAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => Task.FromResult(default(List)); + + private static List Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) { - var online = new List<(string name, string url, string plugin, int index)>(); + var online = new List(); var init = ModInit.AnimeON; - // Визначаємо isAnime згідно стандарту Lampac (Deepwiki): - // isanime = true якщо original_language == "ja" або "zh" bool hasLang = !string.IsNullOrEmpty(original_language); bool isanime = hasLang && (original_language == "ja" || original_language == "zh"); - // AnimeON — аніме-провайдер. Додаємо його: - // - при загальному пошуку (serial == -1), або - // - якщо контент визначений як аніме (isanime), або - // - якщо мова невідома (відсутній original_language) if (init.enable && !init.rip && (serial == -1 || isanime || !hasLang)) { string url = init.overridehost; if (string.IsNullOrEmpty(url) || UpdateService.IsDisconnected()) - url = $"{host}/animeon"; + url = $"{host}/lite/animeon"; - online.Add((init.displayname, url, "animeon", init.displayindex)); + online.Add(new ModuleOnlineItem(init.displayname, url, "animeon", init.displayindex)); } return online; diff --git a/Bamboo/Bamboo.csproj b/Bamboo/Bamboo.csproj index 1fbe365..c280999 100644 --- a/Bamboo/Bamboo.csproj +++ b/Bamboo/Bamboo.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 library true diff --git a/Bamboo/BambooInvoke.cs b/Bamboo/BambooInvoke.cs index ece0bd0..daf59f0 100644 --- a/Bamboo/BambooInvoke.cs +++ b/Bamboo/BambooInvoke.cs @@ -20,13 +20,15 @@ namespace Bamboo private readonly IHybridCache _hybridCache; private readonly Action _onLog; private readonly ProxyManager _proxyManager; + private readonly HttpHydra _httpHydra; - public BambooInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager) + public BambooInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager, HttpHydra httpHydra = null) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; + _httpHydra = httpHydra; } public async Task> Search(string title, string original_title) @@ -50,7 +52,7 @@ namespace Bamboo }; _onLog?.Invoke($"Bamboo search: {searchUrl}"); - string html = await Http.Get(_init.cors(searchUrl), headers: headers, proxy: _proxyManager.Get()); + string html = await HttpGet(searchUrl, headers); if (string.IsNullOrEmpty(html)) return null; @@ -109,7 +111,7 @@ namespace Bamboo }; _onLog?.Invoke($"Bamboo series page: {href}"); - string html = await Http.Get(_init.cors(href), headers: headers, proxy: _proxyManager.Get()); + string html = await HttpGet(href, headers); if (string.IsNullOrEmpty(html)) return null; @@ -183,7 +185,7 @@ namespace Bamboo }; _onLog?.Invoke($"Bamboo movie page: {href}"); - string html = await Http.Get(_init.cors(href), headers: headers, proxy: _proxyManager.Get()); + string html = await HttpGet(href, headers); if (string.IsNullOrEmpty(html)) return null; @@ -311,12 +313,20 @@ namespace Bamboo return HtmlEntity.DeEntitize(value).Trim(); } + private Task HttpGet(string url, List headers) + { + if (_httpHydra != null) + return _httpHydra.Get(url, newheaders: headers); + + return Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get()); + } + public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) { if (init != null && init.rhub && rhub != -1) return TimeSpan.FromMinutes(rhub); - int ctime = AppInit.conf.mikrotik ? mikrotik : AppInit.conf.multiaccess ? init != null && init.cache_time > 0 ? init.cache_time : multiaccess : home; + int ctime = init != null && init.cache_time > 0 ? init.cache_time : multiaccess; if (ctime > multiaccess) ctime = multiaccess; diff --git a/Bamboo/Controller.cs b/Bamboo/Controller.cs index f2a993b..2b07463 100644 --- a/Bamboo/Controller.cs +++ b/Bamboo/Controller.cs @@ -23,27 +23,27 @@ namespace Bamboo.Controllers } [HttpGet] - [Route("bamboo")] + [Route("lite/bamboo")] async public Task Index(long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email, string t, int s = -1, bool rjson = false, string href = null, bool checksearch = false) { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.Bamboo); + var init = loadKit(ModInit.Bamboo); if (!init.enable) return Forbid(); - var invoke = new BambooInvoke(init, hybridCache, OnLog, proxyManager); + var invoke = new BambooInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); if (checksearch) { - if (AppInit.conf?.online?.checkOnlineSearch != true) - return OnError("bamboo", proxyManager); + if (!IsCheckOnlineSearchEnabled()) + return OnError("bamboo", refresh_proxy: true); var searchResults = await invoke.Search(title, original_title); if (searchResults != null && searchResults.Count > 0) return Content("data-json=", "text/plain; charset=utf-8"); - return OnError("bamboo", proxyManager); + return OnError("bamboo", refresh_proxy: true); } string itemUrl = href; @@ -51,14 +51,14 @@ namespace Bamboo.Controllers { var searchResults = await invoke.Search(title, original_title); if (searchResults == null || searchResults.Count == 0) - return OnError("bamboo", proxyManager); + return OnError("bamboo", refresh_proxy: true); if (searchResults.Count > 1) { var similar_tpl = new SimilarTpl(searchResults.Count); foreach (var res in searchResults) { - string link = $"{host}/bamboo?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial={serial}&href={HttpUtility.UrlEncode(res.Url)}"; + string link = $"{host}/lite/bamboo?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial={serial}&href={HttpUtility.UrlEncode(res.Url)}"; similar_tpl.Append(res.Title, string.Empty, string.Empty, link, res.Poster); } @@ -72,7 +72,7 @@ namespace Bamboo.Controllers { var series = await invoke.GetSeriesEpisodes(itemUrl); if (series == null || (series.Sub.Count == 0 && series.Dub.Count == 0)) - return OnError("bamboo", proxyManager); + return OnError("bamboo", refresh_proxy: true); var voice_tpl = new VoiceTpl(); var episode_tpl = new EpisodeTpl(); @@ -88,13 +88,13 @@ namespace Bamboo.Controllers foreach (var voice in availableVoices) { - string voiceLink = $"{host}/bamboo?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&t={voice.key}&href={HttpUtility.UrlEncode(itemUrl)}"; + string voiceLink = $"{host}/lite/bamboo?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&t={voice.key}&href={HttpUtility.UrlEncode(itemUrl)}"; voice_tpl.Append(voice.name, voice.key == t, voiceLink); } var selected = availableVoices.FirstOrDefault(v => v.key == t); if (selected.episodes == null || selected.episodes.Count == 0) - return OnError("bamboo", proxyManager); + return OnError("bamboo", refresh_proxy: true); int index = 1; foreach (var ep in selected.episodes.OrderBy(e => e.Episode ?? int.MaxValue)) @@ -116,7 +116,7 @@ namespace Bamboo.Controllers { var streams = await invoke.GetMovieStreams(itemUrl); if (streams == null || streams.Count == 0) - return OnError("bamboo", proxyManager); + return OnError("bamboo", refresh_proxy: true); var movie_tpl = new MovieTpl(title, original_title); for (int i = 0; i < streams.Count; i++) @@ -166,5 +166,38 @@ namespace Bamboo.Controllers cleaned = cleaned.Replace("?&", "?").Replace("&&", "&").TrimEnd('?', '&'); return cleaned; } + + private static bool IsCheckOnlineSearchEnabled() + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var checkProp = conf?.GetType().GetProperty("checkOnlineSearch", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (checkProp?.GetValue(conf) is bool enabled) + return enabled; + } + catch + { + } + + return true; + } + + private static void OnLog(string message) + { + System.Console.WriteLine(message); + } } } diff --git a/Bamboo/GlobalUsings.cs b/Bamboo/GlobalUsings.cs new file mode 100644 index 0000000..4c00409 --- /dev/null +++ b/Bamboo/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Shared.Services; +global using Shared.Services.Hybrid; +global using Shared.Models.Base; +global using AppInit = Shared.CoreInit; diff --git a/Bamboo/ModInit.cs b/Bamboo/ModInit.cs index 61d1068..521267a 100644 --- a/Bamboo/ModInit.cs +++ b/Bamboo/ModInit.cs @@ -3,6 +3,7 @@ using Shared; using Shared.Engine; using Shared.Models.Online.Settings; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using Microsoft.AspNetCore.Mvc; using Microsoft.CodeAnalysis.Scripting; using Microsoft.Extensions.Caching.Memory; @@ -22,9 +23,9 @@ using System.Threading.Tasks; namespace Bamboo { - public class ModInit + public class ModInit : IModuleLoaded { - public static double Version => 3.6; + public static double Version => 4.0; public static OnlinesSettings Bamboo; public static bool ApnHostProvided; @@ -38,7 +39,7 @@ namespace Bamboo /// /// модуль загружен /// - public static void loaded(InitspaceModel initspace) + public void Loaded(InitspaceModel initspace) { @@ -54,7 +55,7 @@ namespace Bamboo list = new string[] { "socks5://ip:port" } } }; - var conf = ModuleInvoke.Conf("Bamboo", Bamboo); + var conf = ModuleInvoke.Init("Bamboo", JObject.FromObject(Bamboo)); bool hasApn = ApnHelper.TryGetInitConf(conf, out bool apnEnabled, out string apnHost); conf.Remove("apn"); conf.Remove("apn_host"); @@ -73,7 +74,45 @@ namespace Bamboo } // Виводити "уточнити пошук" - AppInit.conf.online.with_search.Add("bamboo"); + RegisterWithSearch("bamboo"); + } + + private static void RegisterWithSearch(string plugin) + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var withSearchProp = conf?.GetType().GetProperty("with_search", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (withSearchProp?.GetValue(conf) is System.Collections.IList list) + { + foreach (var item in list) + { + if (string.Equals(item?.ToString(), plugin, StringComparison.OrdinalIgnoreCase)) + return; + } + + list.Add(plugin); + } + } + catch + { + } + } + + public void Dispose() + { } } diff --git a/Bamboo/OnlineApi.cs b/Bamboo/OnlineApi.cs index be64737..ab01699 100644 --- a/Bamboo/OnlineApi.cs +++ b/Bamboo/OnlineApi.cs @@ -1,28 +1,33 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Shared.Models; -using Shared.Models.Base; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using System.Collections.Generic; +using System.Threading.Tasks; namespace Bamboo { - public class OnlineApi + public class OnlineApi : IModuleOnline { - public static List<(string name, string url, string plugin, int index)> Invoke( - HttpContext httpContext, - IMemoryCache memoryCache, - RequestModel requestInfo, - string host, - OnlineEventsModel args) + public List Invoke(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) { long.TryParse(args.id, out long tmdbid); return Events(host, tmdbid, args.imdb_id, args.kinopoisk_id, args.title, args.original_title, args.original_language, args.year, args.source, args.serial, args.account_email); } - public static List<(string name, string url, string plugin, int index)> Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) + public Task> InvokeAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) + => Task.FromResult(default(List)); + + public List Spider(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => null; + + public Task> SpiderAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => Task.FromResult(default(List)); + + private static List Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) { - var online = new List<(string name, string url, string plugin, int index)>(); + var online = new List(); var init = ModInit.Bamboo; if (init.enable && !init.rip) @@ -36,9 +41,9 @@ namespace Bamboo string url = init.overridehost; if (string.IsNullOrEmpty(url) || UpdateService.IsDisconnected()) - url = $"{host}/bamboo"; + url = $"{host}/lite/bamboo"; - online.Add((init.displayname, url, "bamboo", init.displayindex)); + online.Add(new ModuleOnlineItem(init.displayname, url, "bamboo", init.displayindex)); } return online; diff --git a/JackTor/Controller.cs b/JackTor/Controller.cs index b20ac95..83a820d 100644 --- a/JackTor/Controller.cs +++ b/JackTor/Controller.cs @@ -1,10 +1,9 @@ using JackTor.Models; using Microsoft.AspNetCore.Mvc; using Shared; -using Shared.Engine; using Shared.Models; -using Shared.Models.Online.PiTor; using Shared.Models.Online.Settings; +using Shared.Services.Utilities; using Shared.Models.Templates; using System; using System.Collections.Generic; @@ -27,7 +26,7 @@ namespace JackTor.Controllers } [HttpGet] - [Route("jacktor")] + [Route("lite/jacktor")] async public Task Index( long id, string imdb_id, @@ -46,7 +45,7 @@ namespace JackTor.Controllers { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.Settings); + var init = loadKit(ModInit.Settings); if (!init.enable) return Forbid(); @@ -57,14 +56,14 @@ namespace JackTor.Controllers if (checksearch) { - if (AppInit.conf?.online?.checkOnlineSearch != true) - return OnError("jacktor", proxyManager); + if (!IsCheckOnlineSearchEnabled()) + return OnError("jacktor", refresh_proxy: true); var check = await invoke.Search(title, original_title, year, serial, original_language); if (check.Count > 0) return Content("data-json=", "text/plain; charset=utf-8"); - return OnError("jacktor", proxyManager); + return OnError("jacktor", refresh_proxy: true); } var torrents = await invoke.Search(title, original_title, year, serial, original_language); @@ -98,7 +97,7 @@ namespace JackTor.Controllers { seasonTpl.Append( $"{season} сезон", - $"{host}/jacktor?rjson={rjson}&title={enTitle}&original_title={enOriginal}&year={year}&original_language={original_language}&serial=1&s={season}", + $"{host}/lite/jacktor?rjson={rjson}&title={enTitle}&original_title={enOriginal}&year={year}&original_language={original_language}&serial=1&s={season}", season); } @@ -127,7 +126,7 @@ namespace JackTor.Controllers : $"{seasonLabel} • {torrent.Voice}"; string qualityInfo = $"{torrent.Tracker} / {torrent.QualityLabel} / {torrent.MediaInfo} / ↑{torrent.Seeders}"; - string releaseLink = accsArgs($"{host}/jacktor/serial/{torrent.Rid}?rjson={rjson}&title={enTitle}&original_title={enOriginal}&s={targetSeason}"); + string releaseLink = accsArgs($"{host}/lite/jacktor/serial/{torrent.Rid}?rjson={rjson}&title={enTitle}&original_title={enOriginal}&s={targetSeason}"); similarTpl.Append(releaseName, null, qualityInfo, releaseLink); } @@ -147,7 +146,7 @@ namespace JackTor.Controllers : torrent.Voice; string voiceName = $"{torrent.QualityLabel} / {torrent.MediaInfo} / ↑{torrent.Seeders}"; - string streamLink = accsArgs($"{host}/jacktor/s{torrent.Rid}"); + string streamLink = accsArgs($"{host}/lite/jacktor/s{torrent.Rid}"); movieTpl.Append( voice, @@ -163,10 +162,10 @@ namespace JackTor.Controllers } [HttpGet] - [Route("jacktor/serial/{rid}")] + [Route("lite/jacktor/serial/{rid}")] async public ValueTask Serial(string rid, string account_email, string title, string original_title, int s = 1, bool rjson = false) { - var init = await loadKit(ModInit.Settings); + var init = loadKit(ModInit.Settings); if (!init.enable) return Forbid(); @@ -175,7 +174,7 @@ namespace JackTor.Controllers var invoke = new JackTorInvoke(init, hybridCache, OnLog, proxyManager); if (!invoke.TryGetSource(rid, out JackTorSourceCache source)) - return OnError("jacktor", proxyManager); + return OnError("jacktor", refresh_proxy: true); string memKey = $"jacktor:serial:{rid}"; @@ -185,49 +184,49 @@ namespace JackTor.Controllers { var ts = ResolveProbeTorrentServer(init, account_email); if (string.IsNullOrWhiteSpace(ts.host)) - return OnError("jacktor", proxyManager); + return OnError("jacktor", refresh_proxy: true); - string hashResponse = await Http.Post( + string hashResponse = await httpHydra.Post( $"{ts.host}/torrents", BuildAddPayload(source.SourceUri), - timeoutSeconds: 8, - headers: ts.headers); + statusCodeOK: false, + newheaders: ts.headers); string hash = ExtractHash(hashResponse); if (string.IsNullOrWhiteSpace(hash)) - return OnError("jacktor", proxyManager); + return OnError("jacktor", refresh_proxy: true); Stat stat = null; DateTime deadline = DateTime.Now.AddSeconds(20); while (true) { - stat = await Http.Post( + stat = await httpHydra.Post( $"{ts.host}/torrents", BuildGetPayload(hash), - timeoutSeconds: 3, - headers: ts.headers); + statusCodeOK: false, + newheaders: ts.headers); if (stat?.file_stats != null && stat.file_stats.Length > 0) break; if (DateTime.Now > deadline) { - _ = Http.Post($"{ts.host}/torrents", BuildRemovePayload(hash), headers: ts.headers); - return OnError("jacktor", proxyManager); + _ = httpHydra.Post($"{ts.host}/torrents", BuildRemovePayload(hash), statusCodeOK: false, newheaders: ts.headers); + return OnError("jacktor", refresh_proxy: true); } await Task.Delay(250); } - _ = Http.Post($"{ts.host}/torrents", BuildRemovePayload(hash), headers: ts.headers); + _ = httpHydra.Post($"{ts.host}/torrents", BuildRemovePayload(hash), statusCodeOK: false, newheaders: ts.headers); fileStats = stat.file_stats; hybridCache.Set(memKey, fileStats, DateTime.Now.AddHours(36)); } if (fileStats == null || fileStats.Length == 0) - return OnError("jacktor", proxyManager); + return OnError("jacktor", refresh_proxy: true); var episodeTpl = new EpisodeTpl(); int appended = 0; @@ -242,13 +241,13 @@ namespace JackTor.Controllers title ?? original_title, s.ToString(), file.Id.ToString(), - accsArgs($"{host}/jacktor/s{rid}?tsid={file.Id}")); + accsArgs($"{host}/lite/jacktor/s{rid}?tsid={file.Id}")); appended++; } if (appended == 0) - return OnError("jacktor", proxyManager); + return OnError("jacktor", refresh_proxy: true); return rjson ? Content(episodeTpl.ToJson(), "application/json; charset=utf-8") @@ -257,10 +256,10 @@ namespace JackTor.Controllers } [HttpGet] - [Route("jacktor/s{rid}")] + [Route("lite/jacktor/s{rid}")] async public ValueTask Stream(string rid, int tsid = -1, string account_email = null) { - var init = await loadKit(ModInit.Settings); + var init = loadKit(ModInit.Settings); if (!init.enable) return Forbid(); @@ -269,7 +268,7 @@ namespace JackTor.Controllers var invoke = new JackTorInvoke(init, hybridCache, OnLog, proxyManager); if (!invoke.TryGetSource(rid, out JackTorSourceCache source)) - return OnError("jacktor", proxyManager); + return OnError("jacktor", refresh_proxy: true); int index = tsid != -1 ? tsid : 1; string country = requestInfo.Country; @@ -284,15 +283,15 @@ namespace JackTor.Controllers var headers = HeadersModel.Init("Authorization", $"Basic {CrypTo.Base64($"{login}:{passwd}")}"); headers = HeadersModel.Join(headers, addheaders); - string response = await Http.Post( + string response = await httpHydra.Post( $"{tsHost}/torrents", BuildAddPayload(source.SourceUri), - timeoutSeconds: 5, - headers: headers); + statusCodeOK: false, + newheaders: headers); hash = ExtractHash(response); if (string.IsNullOrWhiteSpace(hash)) - return OnError("jacktor", proxyManager); + return OnError("jacktor", refresh_proxy: true); hybridCache.Set(memKey, hash, DateTime.Now.AddMinutes(1)); } @@ -329,7 +328,7 @@ namespace JackTor.Controllers } if (servers.Count == 0) - return OnError("jacktor", proxyManager); + return OnError("jacktor", refresh_proxy: true); ts = servers[Random.Shared.Next(0, servers.Count)]; hybridCache.Set(tsKey, ts, DateTime.Now.AddHours(4)); @@ -342,7 +341,7 @@ namespace JackTor.Controllers if (init.base_auth != null && init.base_auth.enable) { if (init.torrs == null || init.torrs.Length == 0) - return OnError("jacktor", proxyManager); + return OnError("jacktor", refresh_proxy: true); string tsKey = $"jacktor:ts3:{rid}:{requestInfo.IP}"; if (!hybridCache.TryGetValue(tsKey, out string tsHost)) @@ -355,7 +354,7 @@ namespace JackTor.Controllers } if (init.torrs == null || init.torrs.Length == 0) - return OnError("jacktor", proxyManager); + return OnError("jacktor", refresh_proxy: true); string key = $"jacktor:ts4:{rid}:{requestInfo.IP}"; if (!hybridCache.TryGetValue(key, out string torrentHost)) @@ -474,5 +473,38 @@ namespace JackTor.Controllers return Regex.Replace(url, "(apikey=)[^&]+", "$1***", RegexOptions.IgnoreCase); } + + private static bool IsCheckOnlineSearchEnabled() + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var checkProp = conf?.GetType().GetProperty("checkOnlineSearch", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (checkProp?.GetValue(conf) is bool enabled) + return enabled; + } + catch + { + } + + return true; + } + + private static void OnLog(string message) + { + System.Console.WriteLine(message); + } } } diff --git a/JackTor/GlobalUsings.cs b/JackTor/GlobalUsings.cs new file mode 100644 index 0000000..4c00409 --- /dev/null +++ b/JackTor/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Shared.Services; +global using Shared.Services.Hybrid; +global using Shared.Models.Base; +global using AppInit = Shared.CoreInit; diff --git a/JackTor/JackTor.csproj b/JackTor/JackTor.csproj index 1fbe365..c280999 100644 --- a/JackTor/JackTor.csproj +++ b/JackTor/JackTor.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 library true diff --git a/JackTor/JackTorInvoke.cs b/JackTor/JackTorInvoke.cs index a752809..558cc40 100644 --- a/JackTor/JackTorInvoke.cs +++ b/JackTor/JackTorInvoke.cs @@ -1,5 +1,4 @@ using JackTor.Models; -using Shared.Engine; using Shared.Models; using System; using System.Collections.Generic; diff --git a/JackTor/ModInit.cs b/JackTor/ModInit.cs index 83d42a9..0c0c49d 100644 --- a/JackTor/ModInit.cs +++ b/JackTor/ModInit.cs @@ -2,8 +2,8 @@ using JackTor.Models; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Shared; -using Shared.Engine; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using System; using System.Net.Http; using System.Net.Mime; @@ -15,9 +15,9 @@ using System.Threading.Tasks; namespace JackTor { - public class ModInit + public class ModInit : IModuleLoaded { - public static double Version => 1.0; + public static double Version => 2.0; public static JackTorSettings JackTor; @@ -30,7 +30,7 @@ namespace JackTor /// /// Модуль завантажено. /// - public static void loaded(InitspaceModel initspace) + public void Loaded(InitspaceModel initspace) { JackTor = new JackTorSettings("JackTor", "http://127.0.0.1:9117", streamproxy: false, useproxy: false) { @@ -66,7 +66,7 @@ namespace JackTor } }; - var conf = ModuleInvoke.Conf("JackTor", JackTor) ?? JObject.FromObject(JackTor); + var conf = ModuleInvoke.Init("JackTor", JObject.FromObject(JackTor)) ?? JObject.FromObject(JackTor); JackTor = conf.ToObject(); if (string.IsNullOrWhiteSpace(JackTor.jackett)) @@ -76,7 +76,45 @@ namespace JackTor JackTor.host = JackTor.jackett; // Показувати «уточнити пошук». - AppInit.conf.online.with_search.Add("jacktor"); + RegisterWithSearch("jacktor"); + } + + private static void RegisterWithSearch(string plugin) + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var withSearchProp = conf?.GetType().GetProperty("with_search", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (withSearchProp?.GetValue(conf) is System.Collections.IList list) + { + foreach (var item in list) + { + if (string.Equals(item?.ToString(), plugin, StringComparison.OrdinalIgnoreCase)) + return; + } + + list.Add(plugin); + } + } + catch + { + } + } + + public void Dispose() + { } } diff --git a/JackTor/Models/JackTorModels.cs b/JackTor/Models/JackTorModels.cs index e6cbd16..7d0595c 100644 --- a/JackTor/Models/JackTorModels.cs +++ b/JackTor/Models/JackTorModels.cs @@ -197,4 +197,18 @@ namespace JackTor.Models public int[] Seasons { get; set; } } + + public class FileStat + { + public int Id { get; set; } + + public string Path { get; set; } + + public long Length { get; set; } + } + + public class Stat + { + public FileStat[] file_stats { get; set; } + } } diff --git a/JackTor/OnlineApi.cs b/JackTor/OnlineApi.cs index 3f366b3..592122e 100644 --- a/JackTor/OnlineApi.cs +++ b/JackTor/OnlineApi.cs @@ -2,46 +2,41 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Shared.Models; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using System.Collections.Generic; +using System.Threading.Tasks; namespace JackTor { - public class OnlineApi + public class OnlineApi : IModuleOnline { - public static List<(string name, string url, string plugin, int index)> Invoke( - HttpContext httpContext, - IMemoryCache memoryCache, - RequestModel requestInfo, - string host, - OnlineEventsModel args) + public List Invoke(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) { long.TryParse(args.id, out long tmdbid); return Events(host, tmdbid, args.imdb_id, args.kinopoisk_id, args.title, args.original_title, args.original_language, args.year, args.source, args.serial, args.account_email); } - public static List<(string name, string url, string plugin, int index)> Events( - string host, - long id, - string imdb_id, - long kinopoisk_id, - string title, - string original_title, - string original_language, - int year, - string source, - int serial, - string account_email) + public Task> InvokeAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) + => Task.FromResult(default(List)); + + public List Spider(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => null; + + public Task> SpiderAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => Task.FromResult(default(List)); + + private static List Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) { - var online = new List<(string name, string url, string plugin, int index)>(); + var online = new List(); var init = ModInit.JackTor; if (init.enable && !init.rip) { string url = init.overridehost; if (string.IsNullOrEmpty(url) || UpdateService.IsDisconnected()) - url = $"{host}/jacktor"; + url = $"{host}/lite/jacktor"; - online.Add((init.displayname, url, "jacktor", init.displayindex)); + online.Add(new ModuleOnlineItem(init.displayname, url, "jacktor", init.displayindex)); } return online; diff --git a/KlonFUN/Controller.cs b/KlonFUN/Controller.cs index 278fff3..d9b5470 100644 --- a/KlonFUN/Controller.cs +++ b/KlonFUN/Controller.cs @@ -22,27 +22,27 @@ namespace KlonFUN.Controllers } [HttpGet] - [Route("klonfun")] + [Route("lite/klonfun")] async public Task Index(long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email, string t, int s = -1, bool rjson = false, string href = null, bool checksearch = false) { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.KlonFUN); + var init = loadKit(ModInit.KlonFUN); if (!init.enable) return Forbid(); - var invoke = new KlonFUNInvoke(init, hybridCache, OnLog, proxyManager); + var invoke = new KlonFUNInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); if (checksearch) { - if (AppInit.conf?.online?.checkOnlineSearch != true) - return OnError("klonfun", proxyManager); + if (!IsCheckOnlineSearchEnabled()) + return OnError("klonfun", refresh_proxy: true); var checkResults = await invoke.Search(imdb_id, title, original_title); if (checkResults != null && checkResults.Count > 0) return Content("data-json=", "text/plain; charset=utf-8"); - return OnError("klonfun", proxyManager); + return OnError("klonfun", refresh_proxy: true); } string itemUrl = href; @@ -50,14 +50,14 @@ namespace KlonFUN.Controllers { var searchResults = await invoke.Search(imdb_id, title, original_title); if (searchResults == null || searchResults.Count == 0) - return OnError("klonfun", proxyManager); + return OnError("klonfun", refresh_proxy: true); if (searchResults.Count > 1) { var similarTpl = new SimilarTpl(searchResults.Count); foreach (SearchResult result in searchResults) { - string link = $"{host}/klonfun?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial={serial}&href={HttpUtility.UrlEncode(result.Url)}"; + string link = $"{host}/lite/klonfun?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial={serial}&href={HttpUtility.UrlEncode(result.Url)}"; similarTpl.Append(result.Title, result.Year > 0 ? result.Year.ToString() : string.Empty, string.Empty, link, result.Poster); } @@ -73,7 +73,7 @@ namespace KlonFUN.Controllers if (item == null || string.IsNullOrWhiteSpace(item.PlayerUrl)) { OnLog($"KlonFUN: не знайдено iframe-плеєр для {itemUrl}"); - return OnError("klonfun", proxyManager); + return OnError("klonfun", refresh_proxy: true); } string contentTitle = !string.IsNullOrWhiteSpace(title) ? title : item.Title; @@ -87,7 +87,7 @@ namespace KlonFUN.Controllers { var serialStructure = await invoke.GetSerialStructure(item.PlayerUrl); if (serialStructure == null || serialStructure.Voices.Count == 0) - return OnError("klonfun", proxyManager); + return OnError("klonfun", refresh_proxy: true); if (s == -1) { @@ -118,12 +118,12 @@ namespace KlonFUN.Controllers } if (seasons.Count == 0) - return OnError("klonfun", proxyManager); + return OnError("klonfun", refresh_proxy: true); var seasonTpl = new SeasonTpl(seasons.Count); foreach (int seasonNumber in seasons) { - string link = $"{host}/klonfun?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={seasonNumber}&href={HttpUtility.UrlEncode(itemUrl)}"; + string link = $"{host}/lite/klonfun?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={seasonNumber}&href={HttpUtility.UrlEncode(itemUrl)}"; if (!string.IsNullOrWhiteSpace(t)) link += $"&t={HttpUtility.UrlEncode(t)}"; @@ -140,7 +140,7 @@ namespace KlonFUN.Controllers .ToList(); if (voicesForSeason.Count == 0) - return OnError("klonfun", proxyManager); + return OnError("klonfun", refresh_proxy: true); var selectedVoiceForSeason = voicesForSeason .FirstOrDefault(v => !string.IsNullOrWhiteSpace(t) && v.Key.Equals(t, StringComparison.OrdinalIgnoreCase)) @@ -149,12 +149,12 @@ namespace KlonFUN.Controllers var voiceTpl = new VoiceTpl(voicesForSeason.Count); foreach (var voice in voicesForSeason) { - string voiceLink = $"{host}/klonfun?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={s}&t={HttpUtility.UrlEncode(voice.Key)}&href={HttpUtility.UrlEncode(itemUrl)}"; + string voiceLink = $"{host}/lite/klonfun?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={s}&t={HttpUtility.UrlEncode(voice.Key)}&href={HttpUtility.UrlEncode(itemUrl)}"; voiceTpl.Append(voice.DisplayName, voice.Key.Equals(selectedVoiceForSeason.Key, StringComparison.OrdinalIgnoreCase), voiceLink); } if (!selectedVoiceForSeason.Seasons.TryGetValue(s, out List episodes) || episodes.Count == 0) - return OnError("klonfun", proxyManager); + return OnError("klonfun", refresh_proxy: true); var episodeTpl = new EpisodeTpl(episodes.Count); foreach (SerialEpisode episode in episodes.OrderBy(e => e.Number)) @@ -177,7 +177,7 @@ namespace KlonFUN.Controllers { var streams = await invoke.GetMovieStreams(item.PlayerUrl); if (streams == null || streams.Count == 0) - return OnError("klonfun", proxyManager); + return OnError("klonfun", refresh_proxy: true); var movieTpl = new MovieTpl(contentTitle, contentOriginalTitle, streams.Count); for (int i = 0; i < streams.Count; i++) @@ -232,5 +232,38 @@ namespace KlonFUN.Controllers cleaned = cleaned.Replace("?&", "?").Replace("&&", "&").TrimEnd('?', '&'); return cleaned; } + + private static bool IsCheckOnlineSearchEnabled() + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var checkProp = conf?.GetType().GetProperty("checkOnlineSearch", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (checkProp?.GetValue(conf) is bool enabled) + return enabled; + } + catch + { + } + + return true; + } + + private static void OnLog(string message) + { + System.Console.WriteLine(message); + } } } diff --git a/KlonFUN/GlobalUsings.cs b/KlonFUN/GlobalUsings.cs new file mode 100644 index 0000000..4c00409 --- /dev/null +++ b/KlonFUN/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Shared.Services; +global using Shared.Services.Hybrid; +global using Shared.Models.Base; +global using AppInit = Shared.CoreInit; diff --git a/KlonFUN/KlonFUN.csproj b/KlonFUN/KlonFUN.csproj index 1fbe365..c280999 100644 --- a/KlonFUN/KlonFUN.csproj +++ b/KlonFUN/KlonFUN.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 library true diff --git a/KlonFUN/KlonFUNInvoke.cs b/KlonFUN/KlonFUNInvoke.cs index 2505eea..079cf27 100644 --- a/KlonFUN/KlonFUNInvoke.cs +++ b/KlonFUN/KlonFUNInvoke.cs @@ -28,13 +28,15 @@ namespace KlonFUN private readonly IHybridCache _hybridCache; private readonly Action _onLog; private readonly ProxyManager _proxyManager; + private readonly HttpHydra _httpHydra; - public KlonFUNInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager) + public KlonFUNInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager, HttpHydra httpHydra = null) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; + _httpHydra = httpHydra; } public async Task> Search(string imdbId, string title, string originalTitle) @@ -108,7 +110,7 @@ namespace KlonFUN try { var headers = DefaultHeaders(); - string html = await Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get()); + string html = await HttpGet(url, headers); if (string.IsNullOrWhiteSpace(html)) return null; @@ -362,7 +364,7 @@ namespace KlonFUN var headers = DefaultHeaders(); string form = $"do=search&subaction=search&story={HttpUtility.UrlEncode(query)}"; - string html = await Http.Post(_init.cors(_init.host), form, headers: headers, proxy: _proxyManager.Get()); + string html = await HttpPost(_init.host, form, headers); if (string.IsNullOrWhiteSpace(html)) return null; @@ -465,7 +467,7 @@ namespace KlonFUN requestUrl = ApnHelper.WrapUrl(_init, playerUrl); var headers = DefaultHeaders(); - return await Http.Get(_init.cors(requestUrl), headers: headers, proxy: _proxyManager.Get()); + return await HttpGet(requestUrl, headers); } private static JArray ParsePlayerArray(string html) @@ -699,16 +701,28 @@ namespace KlonFUN return null; } + private Task HttpGet(string url, List headers) + { + if (_httpHydra != null) + return _httpHydra.Get(url, newheaders: headers); + + return Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get()); + } + + private Task HttpPost(string url, string data, List headers) + { + if (_httpHydra != null) + return _httpHydra.Post(url, data, newheaders: headers); + + return Http.Post(_init.cors(url), data, headers: headers, proxy: _proxyManager.Get()); + } + public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) { if (init != null && init.rhub && rhub != -1) return TimeSpan.FromMinutes(rhub); - int ctime = AppInit.conf.mikrotik - ? mikrotik - : AppInit.conf.multiaccess - ? init != null && init.cache_time > 0 ? init.cache_time : multiaccess - : home; + int ctime = init != null && init.cache_time > 0 ? init.cache_time : multiaccess; if (ctime > multiaccess) ctime = multiaccess; diff --git a/KlonFUN/ModInit.cs b/KlonFUN/ModInit.cs index 70e0ec9..c413a40 100644 --- a/KlonFUN/ModInit.cs +++ b/KlonFUN/ModInit.cs @@ -3,6 +3,7 @@ using Shared; using Shared.Engine; using Shared.Models.Online.Settings; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using System; @@ -16,9 +17,9 @@ using System.Threading.Tasks; namespace KlonFUN { - public class ModInit + public class ModInit : IModuleLoaded { - public static double Version => 1.1; + public static double Version => 2.0; public static OnlinesSettings KlonFUN; public static bool ApnHostProvided; @@ -32,7 +33,7 @@ namespace KlonFUN /// /// Модуль завантажено. /// - public static void loaded(InitspaceModel initspace) + public void Loaded(InitspaceModel initspace) { KlonFUN = new OnlinesSettings("KlonFUN", "https://klon.fun", streamproxy: false, useproxy: false) { @@ -47,7 +48,7 @@ namespace KlonFUN } }; - var conf = ModuleInvoke.Conf("KlonFUN", KlonFUN); + var conf = ModuleInvoke.Init("KlonFUN", JObject.FromObject(KlonFUN)); bool hasApn = ApnHelper.TryGetInitConf(conf, out bool apnEnabled, out string apnHost); conf.Remove("apn"); conf.Remove("apn_host"); @@ -67,7 +68,45 @@ namespace KlonFUN } // Додаємо підтримку "уточнити пошук". - AppInit.conf.online.with_search.Add("klonfun"); + RegisterWithSearch("klonfun"); + } + + private static void RegisterWithSearch(string plugin) + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var withSearchProp = conf?.GetType().GetProperty("with_search", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (withSearchProp?.GetValue(conf) is System.Collections.IList list) + { + foreach (var item in list) + { + if (string.Equals(item?.ToString(), plugin, StringComparison.OrdinalIgnoreCase)) + return; + } + + list.Add(plugin); + } + } + catch + { + } + } + + public void Dispose() + { } } diff --git a/KlonFUN/OnlineApi.cs b/KlonFUN/OnlineApi.cs index 27b0955..b7e96d7 100644 --- a/KlonFUN/OnlineApi.cs +++ b/KlonFUN/OnlineApi.cs @@ -1,37 +1,42 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Shared.Models; -using Shared.Models.Base; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using System.Collections.Generic; +using System.Threading.Tasks; namespace KlonFUN { - public class OnlineApi + public class OnlineApi : IModuleOnline { - public static List<(string name, string url, string plugin, int index)> Invoke( - HttpContext httpContext, - IMemoryCache memoryCache, - RequestModel requestInfo, - string host, - OnlineEventsModel args) + public List Invoke(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) { long.TryParse(args.id, out long tmdbid); return Events(host, tmdbid, args.imdb_id, args.kinopoisk_id, args.title, args.original_title, args.original_language, args.year, args.source, args.serial, args.account_email); } - public static List<(string name, string url, string plugin, int index)> Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) + public Task> InvokeAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) + => Task.FromResult(default(List)); + + public List Spider(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => null; + + public Task> SpiderAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => Task.FromResult(default(List)); + + private static List Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) { - var online = new List<(string name, string url, string plugin, int index)>(); + var online = new List(); var init = ModInit.KlonFUN; if (init.enable && !init.rip) { string url = init.overridehost; if (string.IsNullOrEmpty(url) || UpdateService.IsDisconnected()) - url = $"{host}/klonfun"; + url = $"{host}/lite/klonfun"; - online.Add((init.displayname, url, "klonfun", init.displayindex)); + online.Add(new ModuleOnlineItem(init.displayname, url, "klonfun", init.displayindex)); } return online; diff --git a/Makhno/Controller.cs b/Makhno/Controller.cs index 68cf71c..4cd5381 100644 --- a/Makhno/Controller.cs +++ b/Makhno/Controller.cs @@ -13,7 +13,7 @@ using Makhno.Models; namespace Makhno { - [Route("makhno")] + [Route("lite/makhno")] public class MakhnoController : BaseOnlineController { private readonly ProxyManager proxyManager; @@ -28,7 +28,7 @@ namespace Makhno { if (checksearch) { - if (AppInit.conf?.online?.checkOnlineSearch != true) + if (!IsCheckOnlineSearchEnabled()) return OnError(); return Content("data-json=", "text/plain; charset=utf-8"); @@ -36,14 +36,14 @@ namespace Makhno await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.Makhno); + var init = loadKit(ModInit.Makhno); if (!init.enable) return OnError(); Initialization(init); OnLog($"Makhno: {title} (serial={serial}, s={s}, season={season}, t={t})"); - var invoke = new MakhnoInvoke(init, hybridCache, OnLog, proxyManager); + var invoke = new MakhnoInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); var resolved = await ResolvePlaySource(imdb_id, serial, invoke); if (resolved == null || string.IsNullOrEmpty(resolved.PlayUrl)) @@ -61,14 +61,14 @@ namespace Makhno { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.Makhno); + var init = loadKit(ModInit.Makhno); if (!init.enable) return OnError(); Initialization(init); OnLog($"Makhno Play: {title} (s={s}, season={season}, t={t}, episodeId={episodeId}) play={play}"); - var invoke = new MakhnoInvoke(init, hybridCache, OnLog, proxyManager); + var invoke = new MakhnoInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); var resolved = await ResolvePlaySource(imdb_id, serial: 1, invoke); if (resolved == null || string.IsNullOrEmpty(resolved.PlayUrl)) return OnError(); @@ -119,14 +119,14 @@ namespace Makhno { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.Makhno); + var init = loadKit(ModInit.Makhno); if (!init.enable) return OnError(); Initialization(init); OnLog($"Makhno PlayMovie: {title} ({year}) play={play}"); - var invoke = new MakhnoInvoke(init, hybridCache, OnLog, proxyManager); + var invoke = new MakhnoInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); var resolved = await ResolvePlaySource(imdb_id, serial: 0, invoke); if (resolved == null || string.IsNullOrEmpty(resolved.PlayUrl)) return OnError(); @@ -267,7 +267,7 @@ namespace Makhno string voiceParam = seasonVoiceIndex.HasValue ? $"&t={seasonVoiceIndex.Value}" : string.Empty; string seasonName = seasonItem.HasValue ? seasonItem.Value.Season?.Title ?? $"Сезон {seasonNumber}" : $"Сезон {seasonNumber}"; - string link = $"{host}/makhno?imdb_id={imdb_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&season={seasonNumber}{voiceParam}"; + string link = $"{host}/lite/makhno?imdb_id={imdb_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&season={seasonNumber}{voiceParam}"; season_tpl.Append(seasonName, link, seasonNumber.ToString()); } @@ -337,7 +337,7 @@ namespace Makhno string voiceParam = seasonVoiceIndexForTpl.HasValue ? $"&t={seasonVoiceIndexForTpl.Value}" : string.Empty; string seasonName = seasonItem.HasValue ? seasonItem.Value.Season?.Title ?? $"Сезон {seasonNumber}" : $"Сезон {seasonNumber}"; - string link = $"{host}/makhno?imdb_id={imdb_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&season={seasonNumber}{voiceParam}"; + string link = $"{host}/lite/makhno?imdb_id={imdb_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&season={seasonNumber}{voiceParam}"; seasonTplForVoice.Append(seasonName, link, seasonNumber.ToString()); } @@ -354,11 +354,11 @@ namespace Makhno bool sameSeasonSet = seasonsForVoice.Select(s => s.Number).ToHashSet().SetEquals(selectedVoiceSeasonSet); if (hasRequestedSeason && sameSeasonSet) { - voiceLink = $"{host}/makhno?imdb_id={imdb_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&season={requestedSeason}&t={i}"; + voiceLink = $"{host}/lite/makhno?imdb_id={imdb_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&season={requestedSeason}&t={i}"; } else { - voiceLink = $"{host}/makhno?imdb_id={imdb_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&season=-1&t={i}"; + voiceLink = $"{host}/lite/makhno?imdb_id={imdb_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&season=-1&t={i}"; } bool isActive = selectedVoice == i.ToString(); @@ -374,7 +374,7 @@ namespace Makhno bool hasRequestedSeason = seasonsForVoice.Any(s => s.Number == requestedSeason); if (!hasRequestedSeason) { - string redirectUrl = $"{host}/makhno?imdb_id={imdb_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&season=-1&t={voiceIndex}"; + string redirectUrl = $"{host}/lite/makhno?imdb_id={imdb_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&season=-1&t={voiceIndex}"; return UpdateService.Validate(Redirect(redirectUrl)); } @@ -517,5 +517,38 @@ namespace Makhno public string PlayUrl { get; set; } public bool IsSerial { get; set; } } + + private static bool IsCheckOnlineSearchEnabled() + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var checkProp = conf?.GetType().GetProperty("checkOnlineSearch", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (checkProp?.GetValue(conf) is bool enabled) + return enabled; + } + catch + { + } + + return true; + } + + private static void OnLog(string message) + { + System.Console.WriteLine(message); + } } } diff --git a/Makhno/GlobalUsings.cs b/Makhno/GlobalUsings.cs new file mode 100644 index 0000000..4c00409 --- /dev/null +++ b/Makhno/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Shared.Services; +global using Shared.Services.Hybrid; +global using Shared.Models.Base; +global using AppInit = Shared.CoreInit; diff --git a/Makhno/Makhno.csproj b/Makhno/Makhno.csproj index 1fbe365..c280999 100644 --- a/Makhno/Makhno.csproj +++ b/Makhno/Makhno.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 library true diff --git a/Makhno/MakhnoInvoke.cs b/Makhno/MakhnoInvoke.cs index 91f114d..f55632f 100644 --- a/Makhno/MakhnoInvoke.cs +++ b/Makhno/MakhnoInvoke.cs @@ -24,13 +24,15 @@ namespace Makhno private readonly IHybridCache _hybridCache; private readonly Action _onLog; private readonly ProxyManager _proxyManager; + private readonly HttpHydra _httpHydra; - public MakhnoInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager) + public MakhnoInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager, HttpHydra httpHydra = null) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; + _httpHydra = httpHydra; } public async Task GetWormholePlay(string imdbId) @@ -46,7 +48,7 @@ namespace Makhno new HeadersModel("User-Agent", Http.UserAgent) }; - string response = await Http.Get(_init.cors(url), timeoutSeconds: 4, headers: headers, proxy: _proxyManager.Get()); + string response = await HttpGet(url, headers, timeoutSeconds: 4); if (string.IsNullOrWhiteSpace(response)) return null; @@ -84,7 +86,7 @@ namespace Makhno _onLog($"Makhno getting player data from: {requestUrl}"); - var response = await Http.Get(_init.cors(requestUrl), headers: headers, proxy: _proxyManager.Get()); + var response = await HttpGet(requestUrl, headers); if (string.IsNullOrEmpty(response)) return null; @@ -526,6 +528,14 @@ namespace Makhno return normalized; } + private Task HttpGet(string url, List headers, int timeoutSeconds = 15) + { + if (_httpHydra != null) + return _httpHydra.Get(url, newheaders: headers); + + return Http.Get(_init.cors(url), timeoutSeconds: timeoutSeconds, headers: headers, proxy: _proxyManager.Get()); + } + private class WormholeResponse { public string play { get; set; } diff --git a/Makhno/ModInit.cs b/Makhno/ModInit.cs index b268383..b0f106f 100644 --- a/Makhno/ModInit.cs +++ b/Makhno/ModInit.cs @@ -4,6 +4,7 @@ using Shared.Engine; using Newtonsoft.Json.Linq; using Shared.Models.Online.Settings; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using Microsoft.AspNetCore.Mvc; using Microsoft.CodeAnalysis.Scripting; using Microsoft.Extensions.Caching.Memory; @@ -21,9 +22,9 @@ using System.Threading.Tasks; namespace Makhno { - public class ModInit + public class ModInit : IModuleLoaded { - public static double Version => 2.1; + public static double Version => 3.0; public static OnlinesSettings Makhno; public static bool ApnHostProvided; @@ -37,7 +38,7 @@ namespace Makhno /// /// модуль загружен /// - public static void loaded(InitspaceModel initspace) + public void Loaded(InitspaceModel initspace) { Makhno = new OnlinesSettings("Makhno", "https://wh.lme.isroot.in", streamproxy: false, useproxy: false) { @@ -51,7 +52,7 @@ namespace Makhno list = new string[] { "socks5://ip:port" } } }; - var conf = ModuleInvoke.Conf("Makhno", Makhno); + var conf = ModuleInvoke.Init("Makhno", JObject.FromObject(Makhno)); bool hasApn = ApnHelper.TryGetInitConf(conf, out bool apnEnabled, out string apnHost); if (hasApn) { @@ -73,7 +74,45 @@ namespace Makhno } // Виводити "уточнити пошук" - AppInit.conf.online.with_search.Add("makhno"); + RegisterWithSearch("makhno"); + } + + private static void RegisterWithSearch(string plugin) + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var withSearchProp = conf?.GetType().GetProperty("with_search", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (withSearchProp?.GetValue(conf) is System.Collections.IList list) + { + foreach (var item in list) + { + if (string.Equals(item?.ToString(), plugin, StringComparison.OrdinalIgnoreCase)) + return; + } + + list.Add(plugin); + } + } + catch + { + } + } + + public void Dispose() + { } } diff --git a/Makhno/OnlineApi.cs b/Makhno/OnlineApi.cs index 3a32fdd..f8c6a0d 100644 --- a/Makhno/OnlineApi.cs +++ b/Makhno/OnlineApi.cs @@ -1,37 +1,42 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Shared.Models; -using Shared.Models.Base; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using System.Collections.Generic; +using System.Threading.Tasks; namespace Makhno { - public class OnlineApi + public class OnlineApi : IModuleOnline { - public static List<(string name, string url, string plugin, int index)> Invoke( - HttpContext httpContext, - IMemoryCache memoryCache, - RequestModel requestInfo, - string host, - OnlineEventsModel args) + public List Invoke(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) { long.TryParse(args.id, out long tmdbid); return Events(host, tmdbid, args.imdb_id, args.kinopoisk_id, args.title, args.original_title, args.original_language, args.year, args.source, args.serial, args.account_email); } - public static List<(string name, string url, string plugin, int index)> Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) + public Task> InvokeAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) + => Task.FromResult(default(List)); + + public List Spider(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => null; + + public Task> SpiderAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => Task.FromResult(default(List)); + + private static List Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) { - var online = new List<(string name, string url, string plugin, int index)>(); + var online = new List(); var init = ModInit.Makhno; if (init.enable && !init.rip) { string url = init.overridehost; if (string.IsNullOrEmpty(url) || UpdateService.IsDisconnected()) - url = $"{host}/makhno"; + url = $"{host}/lite/makhno"; - online.Add((init.displayname, url, "makhno", init.displayindex)); + online.Add(new ModuleOnlineItem(init.displayname, url, "makhno", init.displayindex)); } return online; diff --git a/Mikai/Controller.cs b/Mikai/Controller.cs index 1325e45..8517763 100644 --- a/Mikai/Controller.cs +++ b/Mikai/Controller.cs @@ -23,48 +23,48 @@ namespace Mikai.Controllers } [HttpGet] - [Route("mikai")] + [Route("lite/mikai")] public async Task Index(long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email, string t, int s = -1, bool rjson = false, bool checksearch = false) { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.Mikai); + var init = loadKit(ModInit.Mikai); if (!init.enable) return Forbid(); - var invoke = new MikaiInvoke(init, hybridCache, OnLog, _proxyManager); + var invoke = new MikaiInvoke(init, hybridCache, OnLog, _proxyManager, httpHydra); if (checksearch) { - if (AppInit.conf?.online?.checkOnlineSearch != true) - return OnError("mikai", _proxyManager); + if (!IsCheckOnlineSearchEnabled()) + return OnError("mikai", refresh_proxy: true); var checkResults = await invoke.Search(title, original_title, year); if (checkResults != null && checkResults.Count > 0) return Content("data-json=", "text/plain; charset=utf-8"); - return OnError("mikai", _proxyManager); + return OnError("mikai", refresh_proxy: true); } OnLog($"Mikai Index: title={title}, original_title={original_title}, serial={serial}, s={s}, t={t}, year={year}"); var searchResults = await invoke.Search(title, original_title, year); if (searchResults == null || searchResults.Count == 0) - return OnError("mikai", _proxyManager); + return OnError("mikai", refresh_proxy: true); var selected = searchResults.FirstOrDefault(); if (selected == null) - return OnError("mikai", _proxyManager); + return OnError("mikai", refresh_proxy: true); var details = await invoke.GetDetails(selected.Id); if (details == null || details.Players == null || details.Players.Count == 0) - return OnError("mikai", _proxyManager); + return OnError("mikai", refresh_proxy: true); bool isSerial = serial == 1 || (serial == -1 && !string.Equals(details.Format, "movie", StringComparison.OrdinalIgnoreCase)); var seasonDetails = await CollectSeasonDetails(details, invoke); var voices = BuildVoices(seasonDetails); if (voices.Count == 0) - return OnError("mikai", _proxyManager); + return OnError("mikai", refresh_proxy: true); string displayTitle = title ?? details.Details?.Names?.Name ?? original_title; @@ -81,14 +81,14 @@ namespace Mikai.Controllers .ToList(); if (seasonNumbers.Count == 0) - return OnError("mikai", _proxyManager); + return OnError("mikai", refresh_proxy: true); if (s == -1) { var seasonTpl = new SeasonTpl(seasonNumbers.Count); foreach (var seasonNumber in seasonNumbers) { - string link = $"{host}/mikai?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={seasonNumber}"; + string link = $"{host}/lite/mikai?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={seasonNumber}"; if (restrictByVoice) link += $"&t={HttpUtility.UrlEncode(t)}"; seasonTpl.Append($"{seasonNumber}", link, seasonNumber.ToString()); @@ -104,7 +104,7 @@ namespace Mikai.Controllers .ToList(); if (!voicesForSeason.Any()) - return OnError("mikai", _proxyManager); + return OnError("mikai", refresh_proxy: true); if (string.IsNullOrEmpty(t)) t = voicesForSeason[0].Key; @@ -118,7 +118,7 @@ namespace Mikai.Controllers { var targetSeasonSet = GetSeasonSet(voice.Value); bool sameSeasonSet = targetSeasonSet.SetEquals(selectedSeasonSet); - string voiceLink = $"{host}/mikai?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1"; + string voiceLink = $"{host}/lite/mikai?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1"; if (sameSeasonSet) voiceLink += $"&s={s}&t={HttpUtility.UrlEncode(voice.Key)}"; else @@ -128,7 +128,7 @@ namespace Mikai.Controllers if (!voices.ContainsKey(t) || !voices[t].Seasons.ContainsKey(s)) { - string redirectUrl = $"{host}/mikai?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s=-1&t={HttpUtility.UrlEncode(t)}"; + string redirectUrl = $"{host}/lite/mikai?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s=-1&t={HttpUtility.UrlEncode(t)}"; return Redirect(redirectUrl); } @@ -143,7 +143,7 @@ namespace Mikai.Controllers if (NeedsResolve(voices[t].ProviderName, streamLink)) { - string callUrl = $"{host}/mikai/play?url={HttpUtility.UrlEncode(streamLink)}&title={HttpUtility.UrlEncode(displayTitle)}&serial=1"; + string callUrl = $"{host}/lite/mikai/play?url={HttpUtility.UrlEncode(streamLink)}&title={HttpUtility.UrlEncode(displayTitle)}&serial=1"; episodeTpl.Append(episodeName, displayTitle, s.ToString(), ep.Number.ToString(), accsArgs(callUrl), "call"); } else @@ -177,14 +177,14 @@ namespace Mikai.Controllers foreach (var ashdiStream in ashdiStreams) { string optionName = $"{voice.DisplayName} {ashdiStream.title}"; - string ashdiCallUrl = $"{host}/mikai/play?url={HttpUtility.UrlEncode(ashdiStream.link)}&title={HttpUtility.UrlEncode(displayTitle)}"; + string ashdiCallUrl = $"{host}/lite/mikai/play?url={HttpUtility.UrlEncode(ashdiStream.link)}&title={HttpUtility.UrlEncode(displayTitle)}"; movieTpl.Append(optionName, accsArgs(ashdiCallUrl), "call"); } continue; } } - string callUrl = $"{host}/mikai/play?url={HttpUtility.UrlEncode(episode.Url)}&title={HttpUtility.UrlEncode(displayTitle)}"; + string callUrl = $"{host}/lite/mikai/play?url={HttpUtility.UrlEncode(episode.Url)}&title={HttpUtility.UrlEncode(displayTitle)}"; movieTpl.Append(voice.DisplayName, accsArgs(callUrl), "call"); } else @@ -195,31 +195,31 @@ namespace Mikai.Controllers } if (movieTpl.data == null || movieTpl.data.Count == 0) - return OnError("mikai", _proxyManager); + return OnError("mikai", refresh_proxy: true); return rjson ? Content(movieTpl.ToJson(), "application/json; charset=utf-8") : Content(movieTpl.ToHtml(), "text/html; charset=utf-8"); } - [HttpGet("mikai/play")] + [HttpGet("lite/mikai/play")] public async Task Play(string url, string title = null, int serial = 0) { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.Mikai); + var init = loadKit(ModInit.Mikai); if (!init.enable) return Forbid(); if (string.IsNullOrEmpty(url)) - return OnError("mikai", _proxyManager); + return OnError("mikai", refresh_proxy: true); - var invoke = new MikaiInvoke(init, hybridCache, OnLog, _proxyManager); + var invoke = new MikaiInvoke(init, hybridCache, OnLog, _proxyManager, httpHydra); OnLog($"Mikai Play: url={url}, serial={serial}"); string streamLink = await invoke.ResolveVideoUrl(url, serial == 1); if (string.IsNullOrEmpty(streamLink)) - return OnError("mikai", _proxyManager); + return OnError("mikai", refresh_proxy: true); List streamHeaders = null; bool forceProxy = false; @@ -462,5 +462,38 @@ namespace Mikai.Controllers return HostStreamProxy(init, link, headers: headers, force_streamproxy: forceProxy); } + + private static bool IsCheckOnlineSearchEnabled() + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var checkProp = conf?.GetType().GetProperty("checkOnlineSearch", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (checkProp?.GetValue(conf) is bool enabled) + return enabled; + } + catch + { + } + + return true; + } + + private static void OnLog(string message) + { + System.Console.WriteLine(message); + } } } diff --git a/Mikai/GlobalUsings.cs b/Mikai/GlobalUsings.cs new file mode 100644 index 0000000..4c00409 --- /dev/null +++ b/Mikai/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Shared.Services; +global using Shared.Services.Hybrid; +global using Shared.Models.Base; +global using AppInit = Shared.CoreInit; diff --git a/Mikai/Mikai.csproj b/Mikai/Mikai.csproj index 1fbe365..c280999 100644 --- a/Mikai/Mikai.csproj +++ b/Mikai/Mikai.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 library true diff --git a/Mikai/MikaiInvoke.cs b/Mikai/MikaiInvoke.cs index 59cee80..bf4cc10 100644 --- a/Mikai/MikaiInvoke.cs +++ b/Mikai/MikaiInvoke.cs @@ -23,13 +23,15 @@ namespace Mikai private readonly IHybridCache _hybridCache; private readonly Action _onLog; private readonly ProxyManager _proxyManager; + private readonly HttpHydra _httpHydra; - public MikaiInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager) + public MikaiInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager, HttpHydra httpHydra = null) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; + _httpHydra = httpHydra; } public async Task> Search(string title, string original_title, int year) @@ -49,7 +51,7 @@ namespace Mikai var headers = DefaultHeaders(); _onLog($"Mikai: using proxy {_proxyManager.CurrentProxyIp} for {searchUrl}"); - string json = await Http.Get(_init.cors(searchUrl), headers: headers, proxy: _proxyManager.Get()); + string json = await HttpGet(searchUrl, headers); if (string.IsNullOrEmpty(json)) return null; @@ -93,7 +95,7 @@ namespace Mikai var headers = DefaultHeaders(); _onLog($"Mikai: using proxy {_proxyManager.CurrentProxyIp} for {url}"); - string json = await Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get()); + string json = await HttpGet(url, headers); if (string.IsNullOrEmpty(json)) return null; @@ -144,7 +146,7 @@ namespace Mikai }; _onLog($"Mikai: using proxy {_proxyManager.CurrentProxyIp} for {requestUrl}"); - string html = await Http.Get(_init.cors(requestUrl), headers: headers, proxy: _proxyManager.Get()); + string html = await HttpGet(requestUrl, headers); if (string.IsNullOrEmpty(html)) return null; @@ -190,7 +192,7 @@ namespace Mikai string requestUrl = AshdiRequestUrl(WithAshdiMultivoice(url, enable: !disableAshdiMultivoiceForVod)); _onLog($"Mikai: using proxy {_proxyManager.CurrentProxyIp} for {requestUrl}"); - string html = await Http.Get(_init.cors(requestUrl), headers: headers, proxy: _proxyManager.Get()); + string html = await HttpGet(requestUrl, headers); if (string.IsNullOrEmpty(html)) return streams; @@ -415,12 +417,20 @@ namespace Mikai return null; } + private Task HttpGet(string url, List headers) + { + if (_httpHydra != null) + return _httpHydra.Get(url, newheaders: headers); + + return Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get()); + } + public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) { if (init != null && init.rhub && rhub != -1) return TimeSpan.FromMinutes(rhub); - int ctime = AppInit.conf.mikrotik ? mikrotik : AppInit.conf.multiaccess ? init != null && init.cache_time > 0 ? init.cache_time : multiaccess : home; + int ctime = init != null && init.cache_time > 0 ? init.cache_time : multiaccess; if (ctime > multiaccess) ctime = multiaccess; diff --git a/Mikai/ModInit.cs b/Mikai/ModInit.cs index 8b2cace..8b4e9c2 100644 --- a/Mikai/ModInit.cs +++ b/Mikai/ModInit.cs @@ -3,6 +3,7 @@ using Shared; using Shared.Engine; using Shared.Models.Online.Settings; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using Microsoft.AspNetCore.Mvc; using Microsoft.CodeAnalysis.Scripting; using Microsoft.Extensions.Caching.Memory; @@ -22,9 +23,9 @@ using System.Threading.Tasks; namespace Mikai { - public class ModInit + public class ModInit : IModuleLoaded { - public static double Version => 3.8; + public static double Version => 4.0; public static OnlinesSettings Mikai; public static bool ApnHostProvided; @@ -38,7 +39,7 @@ namespace Mikai /// /// модуль загружен /// - public static void loaded(InitspaceModel initspace) + public void Loaded(InitspaceModel initspace) { @@ -56,7 +57,7 @@ namespace Mikai } }; - var conf = ModuleInvoke.Conf("Mikai", Mikai); + var conf = ModuleInvoke.Init("Mikai", JObject.FromObject(Mikai)); bool hasApn = ApnHelper.TryGetInitConf(conf, out bool apnEnabled, out string apnHost); conf.Remove("apn"); conf.Remove("apn_host"); @@ -75,7 +76,45 @@ namespace Mikai } // Виводити "уточнити пошук" - AppInit.conf.online.with_search.Add("mikai"); + RegisterWithSearch("mikai"); + } + + private static void RegisterWithSearch(string plugin) + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var withSearchProp = conf?.GetType().GetProperty("with_search", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (withSearchProp?.GetValue(conf) is System.Collections.IList list) + { + foreach (var item in list) + { + if (string.Equals(item?.ToString(), plugin, StringComparison.OrdinalIgnoreCase)) + return; + } + + list.Add(plugin); + } + } + catch + { + } + } + + public void Dispose() + { } } diff --git a/Mikai/OnlineApi.cs b/Mikai/OnlineApi.cs index baaabf3..9eaab55 100644 --- a/Mikai/OnlineApi.cs +++ b/Mikai/OnlineApi.cs @@ -1,47 +1,46 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Shared.Models; -using Shared.Models.Base; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using System.Collections.Generic; +using System.Threading.Tasks; namespace Mikai { - public class OnlineApi + public class OnlineApi : IModuleOnline { - public static List<(string name, string url, string plugin, int index)> Invoke( - HttpContext httpContext, - IMemoryCache memoryCache, - RequestModel requestInfo, - string host, - OnlineEventsModel args) + public List Invoke(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) { long.TryParse(args.id, out long tmdbid); return Events(host, tmdbid, args.imdb_id, args.kinopoisk_id, args.title, args.original_title, args.original_language, args.year, args.source, args.serial, args.account_email); } - public static List<(string name, string url, string plugin, int index)> Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) + public Task> InvokeAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) + => Task.FromResult(default(List)); + + public List Spider(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => null; + + public Task> SpiderAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => Task.FromResult(default(List)); + + private static List Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) { - var online = new List<(string name, string url, string plugin, int index)>(); + var online = new List(); var init = ModInit.Mikai; - // Визначаємо isAnime згідно стандарту Lampac (Deepwiki): - // isanime = true якщо original_language == "ja" або "zh" bool hasLang = !string.IsNullOrEmpty(original_language); bool isanime = hasLang && (original_language == "ja" || original_language == "zh"); - // Mikai — аніме-провайдер. Додаємо його: - // - при загальному пошуку (serial == -1), або - // - якщо контент визначений як аніме (isanime), або - // - якщо мова невідома (відсутній original_language) if (init.enable && !init.rip && (serial == -1 || isanime || !hasLang)) { string url = init.overridehost; if (string.IsNullOrEmpty(url) || UpdateService.IsDisconnected()) - url = $"{host}/mikai"; + url = $"{host}/lite/mikai"; - online.Add((init.displayname, url, "mikai", init.displayindex)); + online.Add(new ModuleOnlineItem(init.displayname, url, "mikai", init.displayindex)); } return online; diff --git a/NMoonAnime/Controller.cs b/NMoonAnime/Controller.cs index cdf81f0..93e8b4a 100644 --- a/NMoonAnime/Controller.cs +++ b/NMoonAnime/Controller.cs @@ -25,35 +25,35 @@ namespace NMoonAnime.Controllers } [HttpGet] - [Route("nmoonanime")] + [Route("lite/nmoonanime")] public async Task Index(long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email, string mal_id, string t, int s = -1, bool rjson = false, bool checksearch = false) { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.NMoonAnime); + var init = loadKit(ModInit.NMoonAnime); if (!init.enable) return Forbid(); - var invoke = new NMoonAnimeInvoke(init, hybridCache, OnLog, proxyManager); + var invoke = new NMoonAnimeInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); string effectiveMalId = ResolveMalId(mal_id, kinopoisk_id, source); if (checksearch) { - if (AppInit.conf?.online?.checkOnlineSearch != true) - return OnError("nmoonanime", proxyManager); + if (!IsCheckOnlineSearchEnabled()) + return OnError("nmoonanime", refresh_proxy: true); var checkResults = await invoke.Search(imdb_id, effectiveMalId, title, year); if (checkResults != null && checkResults.Count > 0) return Content("data-json=", "text/plain; charset=utf-8"); - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); } OnLog($"NMoonAnime: назва={title}, source={source}, imdb={imdb_id}, kinopoisk_id(як mal_id)={kinopoisk_id}, mal_id_ефективний={effectiveMalId}, рік={year}, серіал={serial}, сезон={s}, озвучка={t}"); var seasons = await invoke.Search(imdb_id, effectiveMalId, title, year); if (seasons == null || seasons.Count == 0) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); bool isSeries = serial == 1; NMoonAnimeSeasonContent firstSeasonData = null; @@ -62,7 +62,7 @@ namespace NMoonAnime.Controllers { firstSeasonData = await invoke.GetSeasonContent(seasons[0]); if (firstSeasonData == null || firstSeasonData.Voices.Count == 0) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); isSeries = firstSeasonData.IsSeries; } @@ -75,22 +75,22 @@ namespace NMoonAnime.Controllers return await RenderMovie(invoke, seasons, title, original_title, firstSeasonData, rjson); } - [HttpGet("nmoonanime/play")] + [HttpGet("lite/nmoonanime/play")] public async Task Play(string file, string title = null) { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.NMoonAnime); + var init = loadKit(ModInit.NMoonAnime); if (!init.enable) return Forbid(); if (string.IsNullOrWhiteSpace(file)) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); - var invoke = new NMoonAnimeInvoke(init, hybridCache, OnLog, proxyManager); + var invoke = new NMoonAnimeInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); var streams = invoke.ParseStreams(file); if (streams == null || streams.Count == 0) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); if (streams.Count == 1) { @@ -107,7 +107,7 @@ namespace NMoonAnime.Controllers } if (!streamQuality.Any()) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); var first = streamQuality.Firts(); string json = VideoTpl.ToJson("play", first.link, title ?? string.Empty, streamquality: streamQuality); @@ -133,7 +133,7 @@ namespace NMoonAnime.Controllers .ToList(); if (orderedSeasons.Count == 0) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); if (selectedSeason == -1) { @@ -154,14 +154,14 @@ namespace NMoonAnime.Controllers var currentSeason = orderedSeasons.FirstOrDefault(s => s.SeasonNumber == selectedSeason) ?? orderedSeasons[0]; var seasonData = await invoke.GetSeasonContent(currentSeason); if (seasonData == null) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); var voices = seasonData.Voices .Where(v => v != null && v.Episodes != null && v.Episodes.Count > 0) .ToList(); if (voices.Count == 0) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); int activeVoiceIndex = ParseVoiceIndex(selectedVoice, voices.Count); var voiceTpl = new VoiceTpl(voices.Count); @@ -180,7 +180,7 @@ namespace NMoonAnime.Controllers .ToList(); if (episodes.Count == 0) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); string displayTitle = !string.IsNullOrWhiteSpace(title) ? title @@ -193,7 +193,7 @@ namespace NMoonAnime.Controllers { int episodeNumber = episode.Number <= 0 ? 1 : episode.Number; string episodeName = string.IsNullOrWhiteSpace(episode.Name) ? $"Епізод {episodeNumber}" : episode.Name; - string callUrl = $"{host}/nmoonanime/play?file={HttpUtility.UrlEncode(episode.File)}&title={HttpUtility.UrlEncode(displayTitle)}"; + string callUrl = $"{host}/lite/nmoonanime/play?file={HttpUtility.UrlEncode(episode.File)}&title={HttpUtility.UrlEncode(displayTitle)}"; episodeTpl.Append(episodeName, displayTitle, currentSeason.SeasonNumber.ToString(), episodeNumber.ToString(), accsArgs(callUrl), "call"); } @@ -218,14 +218,14 @@ namespace NMoonAnime.Controllers .FirstOrDefault(); if (currentSeason == null) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); NMoonAnimeSeasonContent seasonData = firstSeasonData; if (seasonData == null || !string.Equals(seasonData.Url, currentSeason.Url, StringComparison.OrdinalIgnoreCase)) seasonData = await invoke.GetSeasonContent(currentSeason); if (seasonData == null || seasonData.Voices.Count == 0) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); string displayTitle = !string.IsNullOrWhiteSpace(title) ? title @@ -249,13 +249,13 @@ namespace NMoonAnime.Controllers continue; string voiceName = string.IsNullOrWhiteSpace(voice.Name) ? $"Озвучка {fallbackIndex}" : voice.Name; - string callUrl = $"{host}/nmoonanime/play?file={HttpUtility.UrlEncode(file)}&title={HttpUtility.UrlEncode(displayTitle)}"; + string callUrl = $"{host}/lite/nmoonanime/play?file={HttpUtility.UrlEncode(file)}&title={HttpUtility.UrlEncode(displayTitle)}"; movieTpl.Append(voiceName, accsArgs(callUrl), "call"); fallbackIndex++; } if (movieTpl.IsEmpty) - return OnError("nmoonanime", proxyManager); + return OnError("nmoonanime", refresh_proxy: true); return rjson ? Content(movieTpl.ToJson(), "application/json; charset=utf-8") @@ -265,7 +265,7 @@ namespace NMoonAnime.Controllers private string BuildIndexUrl(string imdbId, long kinopoiskId, string title, string originalTitle, int year, int serial, string malId, int season, string voice) { var url = new StringBuilder(); - url.Append($"{host}/nmoonanime?imdb_id={HttpUtility.UrlEncode(imdbId)}"); + url.Append($"{host}/lite/nmoonanime?imdb_id={HttpUtility.UrlEncode(imdbId)}"); url.Append($"&kinopoisk_id={kinopoiskId}"); url.Append($"&title={HttpUtility.UrlEncode(title)}"); url.Append($"&original_title={HttpUtility.UrlEncode(originalTitle)}"); @@ -353,5 +353,38 @@ namespace NMoonAnime.Controllers cleaned = cleaned.Replace("?&", "?").Replace("&&", "&").TrimEnd('?', '&'); return cleaned; } + + private static bool IsCheckOnlineSearchEnabled() + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var checkProp = conf?.GetType().GetProperty("checkOnlineSearch", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (checkProp?.GetValue(conf) is bool enabled) + return enabled; + } + catch + { + } + + return true; + } + + private static void OnLog(string message) + { + System.Console.WriteLine(message); + } } } diff --git a/NMoonAnime/GlobalUsings.cs b/NMoonAnime/GlobalUsings.cs new file mode 100644 index 0000000..4c00409 --- /dev/null +++ b/NMoonAnime/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Shared.Services; +global using Shared.Services.Hybrid; +global using Shared.Models.Base; +global using AppInit = Shared.CoreInit; diff --git a/NMoonAnime/ModInit.cs b/NMoonAnime/ModInit.cs index 6ae96b5..129e055 100644 --- a/NMoonAnime/ModInit.cs +++ b/NMoonAnime/ModInit.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json.Linq; using Shared; using Shared.Engine; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using Shared.Models.Online.Settings; using System; using System.Net.Http; @@ -16,9 +17,9 @@ using System.Threading.Tasks; namespace NMoonAnime { - public class ModInit + public class ModInit : IModuleLoaded { - public static double Version => 1.0; + public static double Version => 2.0; public static OnlinesSettings NMoonAnime; @@ -33,7 +34,7 @@ namespace NMoonAnime /// /// Модуль завантажено. /// - public static void loaded(InitspaceModel initspace) + public void Loaded(InitspaceModel initspace) { NMoonAnime = new OnlinesSettings("NMoonAnime", "https://moonanime.art", "https://apx.lme.isroot.in", streamproxy: false, useproxy: false) { @@ -48,7 +49,7 @@ namespace NMoonAnime } }; - var conf = ModuleInvoke.Conf("NMoonAnime", NMoonAnime) ?? JObject.FromObject(NMoonAnime); + var conf = ModuleInvoke.Init("NMoonAnime", JObject.FromObject(NMoonAnime)) ?? JObject.FromObject(NMoonAnime); bool hasApn = ApnHelper.TryGetInitConf(conf, out bool apnEnabled, out string apnHost); conf.Remove("apn"); conf.Remove("apn_host"); @@ -68,7 +69,45 @@ namespace NMoonAnime NMoonAnime.apn = null; } - AppInit.conf.online.with_search.Add("nmoonanime"); + RegisterWithSearch("nmoonanime"); + } + + private static void RegisterWithSearch(string plugin) + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var withSearchProp = conf?.GetType().GetProperty("with_search", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (withSearchProp?.GetValue(conf) is System.Collections.IList list) + { + foreach (var item in list) + { + if (string.Equals(item?.ToString(), plugin, StringComparison.OrdinalIgnoreCase)) + return; + } + + list.Add(plugin); + } + } + catch + { + } + } + + public void Dispose() + { } } diff --git a/NMoonAnime/NMoonAnime.csproj b/NMoonAnime/NMoonAnime.csproj index 1fbe365..c280999 100644 --- a/NMoonAnime/NMoonAnime.csproj +++ b/NMoonAnime/NMoonAnime.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 library true diff --git a/NMoonAnime/NMoonAnimeInvoke.cs b/NMoonAnime/NMoonAnimeInvoke.cs index 3659b15..d21d98c 100644 --- a/NMoonAnime/NMoonAnimeInvoke.cs +++ b/NMoonAnime/NMoonAnimeInvoke.cs @@ -22,6 +22,7 @@ namespace NMoonAnime private readonly IHybridCache _hybridCache; private readonly Action _onLog; private readonly ProxyManager _proxyManager; + private readonly HttpHydra _httpHydra; private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true @@ -35,12 +36,13 @@ namespace NMoonAnime private static readonly UTF8Encoding _utf8Strict = new UTF8Encoding(false, true); private static readonly Encoding _latin1 = Encoding.GetEncoding("ISO-8859-1"); - public NMoonAnimeInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager) + public NMoonAnimeInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager, HttpHydra httpHydra = null) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; + _httpHydra = httpHydra; } public async Task> Search(string imdbId, string malId, string title, int year) @@ -64,7 +66,7 @@ namespace NMoonAnime continue; _onLog($"NMoonAnime: пошук через {searchUrl}"); - string json = await Http.Get(_init.cors(searchUrl), headers: DefaultHeaders(), proxy: _proxyManager.Get()); + string json = await HttpGet(searchUrl, DefaultHeaders()); if (string.IsNullOrWhiteSpace(json)) continue; @@ -108,7 +110,7 @@ namespace NMoonAnime try { _onLog($"NMoonAnime: завантаження сезону {season.Url}"); - string html = await Http.Get(_init.cors(season.Url), headers: DefaultHeaders(), proxy: _proxyManager.Get()); + string html = await HttpGet(season.Url, DefaultHeaders()); if (string.IsNullOrWhiteSpace(html)) return null; @@ -1098,12 +1100,20 @@ namespace NMoonAnime }; } + private Task HttpGet(string url, List headers) + { + if (_httpHydra != null) + return _httpHydra.Get(url, newheaders: headers); + + return Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get()); + } + public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) { if (init != null && init.rhub && rhub != -1) return TimeSpan.FromMinutes(rhub); - int ctime = AppInit.conf.mikrotik ? mikrotik : AppInit.conf.multiaccess ? init != null && init.cache_time > 0 ? init.cache_time : multiaccess : home; + int ctime = init != null && init.cache_time > 0 ? init.cache_time : multiaccess; if (ctime > multiaccess) ctime = multiaccess; diff --git a/NMoonAnime/OnlineApi.cs b/NMoonAnime/OnlineApi.cs index d432193..43afe19 100644 --- a/NMoonAnime/OnlineApi.cs +++ b/NMoonAnime/OnlineApi.cs @@ -1,28 +1,33 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Shared.Models; -using Shared.Models.Base; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using System.Collections.Generic; +using System.Threading.Tasks; namespace NMoonAnime { - public class OnlineApi + public class OnlineApi : IModuleOnline { - public static List<(string name, string url, string plugin, int index)> Invoke( - HttpContext httpContext, - IMemoryCache memoryCache, - RequestModel requestInfo, - string host, - OnlineEventsModel args) + public List Invoke(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) { long.TryParse(args.id, out long tmdbid); return Events(host, tmdbid, args.imdb_id, args.kinopoisk_id, args.title, args.original_title, args.original_language, args.year, args.source, args.serial, args.account_email); } - public static List<(string name, string url, string plugin, int index)> Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) + public Task> InvokeAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) + => Task.FromResult(default(List)); + + public List Spider(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => null; + + public Task> SpiderAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => Task.FromResult(default(List)); + + private static List Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) { - var online = new List<(string name, string url, string plugin, int index)>(); + var online = new List(); var init = ModInit.NMoonAnime; @@ -33,9 +38,9 @@ namespace NMoonAnime { string url = init.overridehost; if (string.IsNullOrEmpty(url) || UpdateService.IsDisconnected()) - url = $"{host}/nmoonanime"; + url = $"{host}/lite/nmoonanime"; - online.Add((init.displayname, url, "nmoonanime", init.displayindex)); + online.Add(new ModuleOnlineItem(init.displayname, url, "nmoonanime", init.displayindex)); } return online; diff --git a/StarLight/Controller.cs b/StarLight/Controller.cs index cc15189..57dc4bf 100644 --- a/StarLight/Controller.cs +++ b/StarLight/Controller.cs @@ -24,27 +24,27 @@ namespace StarLight.Controllers } [HttpGet] - [Route("starlight")] + [Route("lite/starlight")] async public Task Index(long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email, int s = -1, bool rjson = false, string href = null, bool checksearch = false) { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.StarLight); + var init = loadKit(ModInit.StarLight); if (!init.enable) return Forbid(); - var invoke = new StarLightInvoke(init, hybridCache, OnLog, proxyManager); + var invoke = new StarLightInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); if (checksearch) { - if (AppInit.conf?.online?.checkOnlineSearch != true) - return OnError("starlight", proxyManager); + if (!IsCheckOnlineSearchEnabled()) + return OnError("starlight", refresh_proxy: true); var searchResults = await invoke.Search(title, original_title); if (searchResults != null && searchResults.Count > 0) return Content("data-json=", "text/plain; charset=utf-8"); - return OnError("starlight", proxyManager); + return OnError("starlight", refresh_proxy: true); } string itemUrl = href; @@ -52,14 +52,14 @@ namespace StarLight.Controllers { var searchResults = await invoke.Search(title, original_title); if (searchResults == null || searchResults.Count == 0) - return OnError("starlight", proxyManager); + return OnError("starlight", refresh_proxy: true); if (searchResults.Count > 1) { var similar_tpl = new SimilarTpl(searchResults.Count); foreach (var res in searchResults) { - string link = $"{host}/starlight?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial={serial}&href={HttpUtility.UrlEncode(res.Href)}"; + string link = $"{host}/lite/starlight?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial={serial}&href={HttpUtility.UrlEncode(res.Href)}"; similar_tpl.Append(res.Title, string.Empty, string.Empty, link, string.Empty); } @@ -71,7 +71,7 @@ namespace StarLight.Controllers var project = await invoke.GetProject(itemUrl); if (project == null) - return OnError("starlight", proxyManager); + return OnError("starlight", refresh_proxy: true); if (serial == 1 && project.Seasons.Count > 0) { @@ -82,7 +82,7 @@ namespace StarLight.Controllers { var seasonInfo = project.Seasons[i]; string seasonName = string.IsNullOrEmpty(seasonInfo.Title) ? $"Сезон {i + 1}" : seasonInfo.Title; - string link = $"{host}/starlight?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={i}&href={HttpUtility.UrlEncode(itemUrl)}"; + string link = $"{host}/lite/starlight?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={i}&href={HttpUtility.UrlEncode(itemUrl)}"; season_tpl.Append(seasonName, link, i.ToString()); } @@ -90,13 +90,13 @@ namespace StarLight.Controllers } if (s < 0 || s >= project.Seasons.Count) - return OnError("starlight", proxyManager); + return OnError("starlight", refresh_proxy: true); var season = project.Seasons[s]; string seasonSlug = season.Slug; var episodes = invoke.GetEpisodes(project, seasonSlug); if (episodes == null || episodes.Count == 0) - return OnError("starlight", proxyManager); + return OnError("starlight", refresh_proxy: true); var episode_tpl = new EpisodeTpl(); int index = 1; @@ -114,7 +114,7 @@ namespace StarLight.Controllers continue; string episodeName = string.IsNullOrEmpty(ep.Title) ? $"Епізод {index}" : ep.Title; - string callUrl = $"{host}/starlight/play?hash={HttpUtility.UrlEncode(ep.Hash)}&title={HttpUtility.UrlEncode(title ?? original_title)}"; + string callUrl = $"{host}/lite/starlight/play?hash={HttpUtility.UrlEncode(ep.Hash)}&title={HttpUtility.UrlEncode(title ?? original_title)}"; episode_tpl.Append(episodeName, title ?? original_title, seasonNumber, index.ToString("D2"), accsArgs(callUrl), "call"); index++; } @@ -128,9 +128,9 @@ namespace StarLight.Controllers hash = project.Episodes.FirstOrDefault(e => !string.IsNullOrEmpty(e.Hash))?.Hash; if (string.IsNullOrEmpty(hash)) - return OnError("starlight", proxyManager); + return OnError("starlight", refresh_proxy: true); - string callUrl = $"{host}/starlight/play?hash={HttpUtility.UrlEncode(hash)}&title={HttpUtility.UrlEncode(title ?? original_title)}"; + string callUrl = $"{host}/lite/starlight/play?hash={HttpUtility.UrlEncode(hash)}&title={HttpUtility.UrlEncode(title ?? original_title)}"; var movie_tpl = new MovieTpl(title, original_title, 1); movie_tpl.Append(string.IsNullOrEmpty(title) ? "StarLight" : title, accsArgs(callUrl), "call"); @@ -139,22 +139,22 @@ namespace StarLight.Controllers } [HttpGet] - [Route("starlight/play")] + [Route("lite/starlight/play")] async public Task Play(string hash, string title) { await UpdateService.ConnectAsync(host); if (string.IsNullOrEmpty(hash)) - return OnError("starlight", proxyManager); + return OnError("starlight", refresh_proxy: true); - var init = await loadKit(ModInit.StarLight); + var init = loadKit(ModInit.StarLight); if (!init.enable) return Forbid(); - var invoke = new StarLightInvoke(init, hybridCache, OnLog, proxyManager); + var invoke = new StarLightInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); var result = await invoke.ResolveStream(hash); if (result == null || string.IsNullOrEmpty(result.Stream)) - return OnError("starlight", proxyManager); + return OnError("starlight", refresh_proxy: true); string videoTitle = title ?? result.Name ?? ""; @@ -266,5 +266,38 @@ namespace StarLight.Controllers return DateTime.TryParse(episode.Date, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt) ? dt : null; } + + private static bool IsCheckOnlineSearchEnabled() + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var checkProp = conf?.GetType().GetProperty("checkOnlineSearch", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (checkProp?.GetValue(conf) is bool enabled) + return enabled; + } + catch + { + } + + return true; + } + + private static void OnLog(string message) + { + System.Console.WriteLine(message); + } } } diff --git a/StarLight/GlobalUsings.cs b/StarLight/GlobalUsings.cs new file mode 100644 index 0000000..4c00409 --- /dev/null +++ b/StarLight/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Shared.Services; +global using Shared.Services.Hybrid; +global using Shared.Models.Base; +global using AppInit = Shared.CoreInit; diff --git a/StarLight/ModInit.cs b/StarLight/ModInit.cs index 7f3971e..778e234 100644 --- a/StarLight/ModInit.cs +++ b/StarLight/ModInit.cs @@ -2,6 +2,7 @@ using Newtonsoft.Json.Linq; using Shared; using Shared.Engine; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using Shared.Models.Online.Settings; using Microsoft.AspNetCore.Mvc; using Microsoft.CodeAnalysis.Scripting; @@ -22,9 +23,9 @@ using System.Threading.Tasks; namespace StarLight { - public class ModInit + public class ModInit : IModuleLoaded { - public static double Version => 3.3; + public static double Version => 4.0; public static OnlinesSettings StarLight; public static bool ApnHostProvided; @@ -38,7 +39,7 @@ namespace StarLight /// /// модуль загружен /// - public static void loaded(InitspaceModel initspace) + public void Loaded(InitspaceModel initspace) { @@ -54,7 +55,7 @@ namespace StarLight list = new string[] { "socks5://ip:port" } } }; - var conf = ModuleInvoke.Conf("StarLight", StarLight); + var conf = ModuleInvoke.Init("StarLight", JObject.FromObject(StarLight)); bool hasApn = ApnHelper.TryGetInitConf(conf, out bool apnEnabled, out string apnHost); conf.Remove("apn"); conf.Remove("apn_host"); @@ -73,7 +74,45 @@ namespace StarLight } // Виводити "уточнити пошук" - AppInit.conf.online.with_search.Add("starlight"); + RegisterWithSearch("starlight"); + } + + private static void RegisterWithSearch(string plugin) + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var withSearchProp = conf?.GetType().GetProperty("with_search", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (withSearchProp?.GetValue(conf) is System.Collections.IList list) + { + foreach (var item in list) + { + if (string.Equals(item?.ToString(), plugin, StringComparison.OrdinalIgnoreCase)) + return; + } + + list.Add(plugin); + } + } + catch + { + } + } + + public void Dispose() + { } } diff --git a/StarLight/OnlineApi.cs b/StarLight/OnlineApi.cs index 80d91fc..c2d4464 100644 --- a/StarLight/OnlineApi.cs +++ b/StarLight/OnlineApi.cs @@ -1,29 +1,34 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Shared.Models; -using Shared.Models.Base; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace StarLight { - public class OnlineApi + public class OnlineApi : IModuleOnline { - public static List<(string name, string url, string plugin, int index)> Invoke( - HttpContext httpContext, - IMemoryCache memoryCache, - RequestModel requestInfo, - string host, - OnlineEventsModel args) + public List Invoke(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) { long.TryParse(args.id, out long tmdbid); return Events(host, tmdbid, args.imdb_id, args.kinopoisk_id, args.title, args.original_title, args.original_language, args.year, args.source, args.serial, args.account_email); } - public static List<(string name, string url, string plugin, int index)> Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) + public Task> InvokeAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) + => Task.FromResult(default(List)); + + public List Spider(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => null; + + public Task> SpiderAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => Task.FromResult(default(List)); + + private static List Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) { - var online = new List<(string name, string url, string plugin, int index)>(); + var online = new List(); if (!string.Equals(original_language, "uk", StringComparison.OrdinalIgnoreCase)) return online; @@ -33,9 +38,9 @@ namespace StarLight { string url = init.overridehost; if (string.IsNullOrEmpty(url) || UpdateService.IsDisconnected()) - url = $"{host}/starlight"; + url = $"{host}/lite/starlight"; - online.Add((init.displayname, url, "starlight", init.displayindex)); + online.Add(new ModuleOnlineItem(init.displayname, url, "starlight", init.displayindex)); } return online; diff --git a/StarLight/StarLight.csproj b/StarLight/StarLight.csproj index 1fbe365..c280999 100644 --- a/StarLight/StarLight.csproj +++ b/StarLight/StarLight.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 library true diff --git a/StarLight/StarLightInvoke.cs b/StarLight/StarLightInvoke.cs index bfe7134..de0fa88 100644 --- a/StarLight/StarLightInvoke.cs +++ b/StarLight/StarLightInvoke.cs @@ -24,13 +24,15 @@ namespace StarLight private readonly IHybridCache _hybridCache; private readonly Action _onLog; private readonly ProxyManager _proxyManager; + private readonly HttpHydra _httpHydra; - public StarLightInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager) + public StarLightInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager, HttpHydra httpHydra = null) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; + _httpHydra = httpHydra; } public async Task> Search(string title, string original_title) @@ -54,7 +56,7 @@ namespace StarLight try { _onLog?.Invoke($"StarLight search: {url}"); - string payload = await Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get()); + string payload = await HttpGet(url, headers); if (string.IsNullOrEmpty(payload)) return null; @@ -112,7 +114,7 @@ namespace StarLight try { _onLog?.Invoke($"StarLight project: {href}"); - string payload = await Http.Get(_init.cors(href), headers: headers, proxy: _proxyManager.Get()); + string payload = await HttpGet(href, headers); if (string.IsNullOrEmpty(payload)) return null; @@ -193,7 +195,7 @@ namespace StarLight try { _onLog?.Invoke($"StarLight season: {seasonUrl}"); - string payload = await Http.Get(_init.cors(seasonUrl), headers: headers, proxy: _proxyManager.Get()); + string payload = await HttpGet(seasonUrl, headers); if (string.IsNullOrEmpty(payload)) continue; @@ -279,7 +281,7 @@ namespace StarLight try { _onLog?.Invoke($"StarLight stream: {url}"); - string payload = await Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get()); + string payload = await HttpGet(url, headers); if (string.IsNullOrEmpty(payload)) return null; @@ -338,12 +340,20 @@ namespace StarLight return $"{_init.host}{path}"; } + private Task HttpGet(string url, List headers) + { + if (_httpHydra != null) + return _httpHydra.Get(url, newheaders: headers); + + return Http.Get(_init.cors(url), headers: headers, proxy: _proxyManager.Get()); + } + public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) { if (init != null && init.rhub && rhub != -1) return TimeSpan.FromMinutes(rhub); - int ctime = AppInit.conf.mikrotik ? mikrotik : AppInit.conf.multiaccess ? init != null && init.cache_time > 0 ? init.cache_time : multiaccess : home; + int ctime = init != null && init.cache_time > 0 ? init.cache_time : multiaccess; if (ctime > multiaccess) ctime = multiaccess; diff --git a/Uaflix/Controller.cs b/Uaflix/Controller.cs index c0c2776..45a30f1 100644 --- a/Uaflix/Controller.cs +++ b/Uaflix/Controller.cs @@ -28,28 +28,28 @@ namespace Uaflix.Controllers } [HttpGet] - [Route("uaflix")] + [Route("lite/uaflix")] async public Task Index(long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email, string t, int s = -1, int e = -1, bool play = false, bool rjson = false, string href = null, bool checksearch = false) { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.UaFlix); - if (await IsBadInitialization(init)) - return Forbid(); + if (await IsRequestBlocked(rch: false)) + return badInitMsg; + var init = this.init; OnLog($"=== UAFLIX INDEX START ==="); OnLog($"Uaflix Index: title={title}, serial={serial}, s={s}, play={play}, href={href}, checksearch={checksearch}"); OnLog($"Uaflix Index: kinopoisk_id={kinopoisk_id}, imdb_id={imdb_id}, id={id}"); OnLog($"Uaflix Index: year={year}, source={source}, t={t}, e={e}, rjson={rjson}"); var auth = new UaflixAuth(init, memoryCache, OnLog, proxyManager); - var invoke = new UaflixInvoke(init, hybridCache, OnLog, proxyManager, auth); + var invoke = new UaflixInvoke(init, hybridCache, OnLog, proxyManager, auth, httpHydra); // Обробка параметра checksearch - повертаємо спеціальну відповідь для валідації if (checksearch) { - if (AppInit.conf?.online?.checkOnlineSearch != true) - return OnError("uaflix", proxyManager); + if (!IsCheckOnlineSearchEnabled()) + return OnError("uaflix", refresh_proxy: true); try { @@ -63,13 +63,13 @@ namespace Uaflix.Controllers OnLog("checksearch: Контент не знайдено"); OnLog("=== RETURN: checksearch OnError ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } catch (Exception ex) { OnLog($"checksearch: помилка - {ex.Message}"); OnLog("=== RETURN: checksearch exception OnError ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } } @@ -80,7 +80,7 @@ namespace Uaflix.Controllers if (string.IsNullOrWhiteSpace(urlToParse)) { OnLog("=== RETURN: play missing url OnError ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } var playResult = await invoke.ParseEpisode(urlToParse); @@ -91,7 +91,7 @@ namespace Uaflix.Controllers } OnLog("=== RETURN: play no streams ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } // Якщо є episode_url але немає play=true, це виклик для отримання інформації про стрім (для method: 'call') @@ -109,7 +109,7 @@ namespace Uaflix.Controllers } OnLog("=== RETURN: call method no streams ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } string filmUrl = href; @@ -121,7 +121,7 @@ namespace Uaflix.Controllers { OnLog("No search results found"); OnLog("=== RETURN: no search results OnError ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } var selectedResult = invoke.SelectBestSearchResult(searchResults, title, original_title, year); @@ -142,7 +142,7 @@ namespace Uaflix.Controllers var similar_tpl = new SimilarTpl(orderedResults.Count); foreach (var res in orderedResults) { - string link = $"{host}/uaflix?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial={serial}&href={HttpUtility.UrlEncode(res.Url)}"; + string link = $"{host}/lite/uaflix?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial={serial}&href={HttpUtility.UrlEncode(res.Url)}"; string y = res.Year > 0 ? res.Year.ToString() : string.Empty; string details = res.Category switch { @@ -168,7 +168,7 @@ namespace Uaflix.Controllers { OnLog("No voices found in aggregated structure"); OnLog("=== RETURN: no voices OnError ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } OnLog($"Structure aggregated successfully: {structure.Voices.Count} voices, URL: {filmUrl}"); @@ -226,13 +226,13 @@ namespace Uaflix.Controllers { OnLog("No seasons with valid episodes found in structure"); OnLog("=== RETURN: no valid seasons OnError ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } var season_tpl = new SeasonTpl(seasonsWithValidEpisodes.Count); foreach (var season in seasonsWithValidEpisodes) { - string link = $"{host}/uaflix?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={season}&href={HttpUtility.UrlEncode(filmUrl)}"; + string link = $"{host}/lite/uaflix?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={season}&href={HttpUtility.UrlEncode(filmUrl)}"; if (restrictByVoice) link += $"&t={HttpUtility.UrlEncode(t)}"; season_tpl.Append($"{season}", link, season.ToString()); @@ -260,7 +260,7 @@ namespace Uaflix.Controllers { OnLog($"No voices found for season {s}"); OnLog("=== RETURN: no voices for season OnError ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } // Автоматично вибираємо першу озвучку якщо не вказана @@ -288,7 +288,7 @@ namespace Uaflix.Controllers bool sameSeasonSet = targetSeasonSet.SetEquals(selectedSeasonSet); bool needSeasonReset = (selectedIsAshdi || targetIsAshdi) && !sameSeasonSet; - string voiceLink = $"{host}/uaflix?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&href={HttpUtility.UrlEncode(filmUrl)}"; + string voiceLink = $"{host}/lite/uaflix?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&href={HttpUtility.UrlEncode(filmUrl)}"; if (needSeasonReset) voiceLink += $"&s=-1&t={HttpUtility.UrlEncode(voice.DisplayName)}"; else @@ -304,7 +304,7 @@ namespace Uaflix.Controllers { OnLog($"Voice '{t}' not found in structure"); OnLog("=== RETURN: voice not found OnError ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } if (!structure.Voices[t].Seasons.ContainsKey(s)) @@ -312,13 +312,13 @@ namespace Uaflix.Controllers OnLog($"Season {s} not found for voice '{t}'"); if (IsAshdiVoice(structure.Voices[t])) { - string redirectUrl = $"{host}/uaflix?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s=-1&t={HttpUtility.UrlEncode(t)}&href={HttpUtility.UrlEncode(filmUrl)}"; + string redirectUrl = $"{host}/lite/uaflix?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s=-1&t={HttpUtility.UrlEncode(t)}&href={HttpUtility.UrlEncode(filmUrl)}"; OnLog($"Ashdi voice missing season, redirect to season selector: {redirectUrl}"); return Redirect(redirectUrl); } OnLog("=== RETURN: season not found for voice OnError ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } var episodes = structure.Voices[t].Seasons[s]; @@ -334,7 +334,7 @@ namespace Uaflix.Controllers { // Для zetvideo-vod та ashdi-vod використовуємо URL епізоду для виклику // Потрібно передати URL епізоду в інший параметр, щоб не плутати з play=true - string callUrl = $"{host}/uaflix?episode_url={HttpUtility.UrlEncode(ep.File)}&imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial={serial}&s={s}&e={ep.Number}"; + string callUrl = $"{host}/lite/uaflix?episode_url={HttpUtility.UrlEncode(ep.File)}&imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial={serial}&s={s}&e={ep.Number}"; episode_tpl.Append( name: ep.Title, title: title, @@ -378,7 +378,7 @@ namespace Uaflix.Controllers // Fallback: якщо жоден з умов не виконався OnLog($"Fallback: s={s}, t={t}"); OnLog("=== RETURN: fallback OnError ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } else // Фільм { @@ -386,7 +386,7 @@ namespace Uaflix.Controllers if (playResult?.streams == null || playResult.streams.Count == 0) { OnLog("=== RETURN: movie no streams ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } var tpl = new MovieTpl(title, original_title, playResult.streams.Count); @@ -407,7 +407,7 @@ namespace Uaflix.Controllers if (tpl.data == null || tpl.data.Count == 0) { OnLog("=== RETURN: movie template empty ==="); - return OnError("uaflix", proxyManager); + return OnError("uaflix", refresh_proxy: true); } OnLog("=== RETURN: movie template ==="); @@ -469,5 +469,38 @@ namespace Uaflix.Controllers .Select(kv => kv.Key) .ToHashSet(); } + + private static bool IsCheckOnlineSearchEnabled() + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var checkProp = conf?.GetType().GetProperty("checkOnlineSearch", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (checkProp?.GetValue(conf) is bool enabled) + return enabled; + } + catch + { + } + + return true; + } + + private static void OnLog(string message) + { + System.Console.WriteLine(message); + } } } diff --git a/Uaflix/GlobalUsings.cs b/Uaflix/GlobalUsings.cs new file mode 100644 index 0000000..4c00409 --- /dev/null +++ b/Uaflix/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Shared.Services; +global using Shared.Services.Hybrid; +global using Shared.Models.Base; +global using AppInit = Shared.CoreInit; diff --git a/Uaflix/ModInit.cs b/Uaflix/ModInit.cs index a1c993e..1d21425 100644 --- a/Uaflix/ModInit.cs +++ b/Uaflix/ModInit.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json.Linq; using Shared; using Shared.Engine; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using System; using System.Net.Http; using System.Net.Mime; @@ -16,9 +17,9 @@ using Uaflix.Models; namespace Uaflix { - public class ModInit + public class ModInit : IModuleLoaded { - public static double Version => 4.0; + public static double Version => 5.0; public static UaflixSettings UaFlix; @@ -33,7 +34,7 @@ namespace Uaflix /// /// Модуль завантажено. /// - public static void loaded(InitspaceModel initspace) + public void Loaded(InitspaceModel initspace) { UaFlix = new UaflixSettings("Uaflix", "https://uafix.net", streamproxy: false, useproxy: false) { @@ -53,7 +54,7 @@ namespace Uaflix } }; - var conf = ModuleInvoke.Conf("Uaflix", UaFlix) ?? JObject.FromObject(UaFlix); + var conf = ModuleInvoke.Init("Uaflix", JObject.FromObject(UaFlix)) ?? JObject.FromObject(UaFlix); bool hasApn = ApnHelper.TryGetInitConf(conf, out bool apnEnabled, out string apnHost); conf.Remove("apn"); conf.Remove("apn_host"); @@ -74,7 +75,45 @@ namespace Uaflix } // Показувати «уточнити пошук». - AppInit.conf.online.with_search.Add("uaflix"); + RegisterWithSearch("uaflix"); + } + + private static void RegisterWithSearch(string plugin) + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var withSearchProp = conf?.GetType().GetProperty("with_search", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (withSearchProp?.GetValue(conf) is System.Collections.IList list) + { + foreach (var item in list) + { + if (string.Equals(item?.ToString(), plugin, StringComparison.OrdinalIgnoreCase)) + return; + } + + list.Add(plugin); + } + } + catch + { + } + } + + public void Dispose() + { } } diff --git a/Uaflix/OnlineApi.cs b/Uaflix/OnlineApi.cs index 7452f36..f4ff9c5 100644 --- a/Uaflix/OnlineApi.cs +++ b/Uaflix/OnlineApi.cs @@ -1,37 +1,42 @@ -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Shared.Models; -using Shared.Models.Base; using Shared.Models.Module; -using System.Collections.Generic; - -namespace Uaflix -{ - public class OnlineApi +using Shared.Models.Module.Interfaces; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Uaflix +{ + public class OnlineApi : IModuleOnline { - public static List<(string name, string url, string plugin, int index)> Invoke( - HttpContext httpContext, - IMemoryCache memoryCache, - RequestModel requestInfo, - string host, - OnlineEventsModel args) + public List Invoke(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) { long.TryParse(args.id, out long tmdbid); return Events(host, tmdbid, args.imdb_id, args.kinopoisk_id, args.title, args.original_title, args.original_language, args.year, args.source, args.serial, args.account_email); } - public static List<(string name, string url, string plugin, int index)> Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) + public Task> InvokeAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) + => Task.FromResult(default(List)); + + public List Spider(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => null; + + public Task> SpiderAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => Task.FromResult(default(List)); + + private static List Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) { - var online = new List<(string name, string url, string plugin, int index)>(); + var online = new List(); var init = ModInit.UaFlix; if (init.enable && !init.rip) { string url = init.overridehost; if (string.IsNullOrEmpty(url) || UpdateService.IsDisconnected()) - url = $"{host}/uaflix"; + url = $"{host}/lite/uaflix"; - online.Add((init.displayname, url, "uaflix", init.displayindex)); + online.Add(new ModuleOnlineItem(init.displayname, url, "uaflix", init.displayindex)); } return online; diff --git a/Uaflix/Uaflix.csproj b/Uaflix/Uaflix.csproj index c26a806..9512ffc 100644 --- a/Uaflix/Uaflix.csproj +++ b/Uaflix/Uaflix.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 library true diff --git a/Uaflix/UaflixInvoke.cs b/Uaflix/UaflixInvoke.cs index 5ca6303..2558c15 100644 --- a/Uaflix/UaflixInvoke.cs +++ b/Uaflix/UaflixInvoke.cs @@ -28,14 +28,16 @@ namespace Uaflix private readonly Action _onLog; private readonly ProxyManager _proxyManager; private readonly UaflixAuth _auth; + private readonly HttpHydra _httpHydra; - public UaflixInvoke(UaflixSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager, UaflixAuth auth) + public UaflixInvoke(UaflixSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager, UaflixAuth auth, HttpHydra httpHydra = null) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; _auth = auth; + _httpHydra = httpHydra; } string AshdiRequestUrl(string url) @@ -76,7 +78,6 @@ namespace Uaflix if (string.IsNullOrWhiteSpace(url)) return null; - string requestUrl = _init.cors(url); bool withAuth = ShouldUseAuth(url); var requestHeaders = headers != null ? new List(headers) : new List(); @@ -86,6 +87,26 @@ namespace Uaflix _auth.ApplyCookieHeader(requestHeaders, cookie); } + if (_httpHydra != null) + { + string content = await _httpHydra.Get(url, newheaders: requestHeaders, statusCodeOK: false); + + if (string.IsNullOrWhiteSpace(content) + && retryOnUnauthorized + && withAuth + && _auth != null + && _auth.CanUseCredentials) + { + _onLog($"UaflixAuth: порожня відповідь для {url}, виконую повторну авторизацію"); + string refreshedCookie = await _auth.GetCookieHeaderAsync(forceRefresh: true); + _auth.ApplyCookieHeader(requestHeaders, refreshedCookie); + content = await _httpHydra.Get(url, newheaders: requestHeaders, statusCodeOK: false); + } + + return string.IsNullOrWhiteSpace(content) ? null : content; + } + + string requestUrl = _init.cors(url); var response = await Http.BaseGet(requestUrl, headers: requestHeaders, timeoutSeconds: timeoutSeconds, @@ -1790,7 +1811,7 @@ namespace Uaflix if (init != null && init.rhub && rhub != -1) return TimeSpan.FromMinutes(rhub); - int ctime = AppInit.conf.mikrotik ? mikrotik : AppInit.conf.multiaccess ? init != null && init.cache_time > 0 ? init.cache_time : multiaccess : home; + int ctime = init != null && init.cache_time > 0 ? init.cache_time : multiaccess; if (ctime > multiaccess) ctime = multiaccess; @@ -1805,9 +1826,9 @@ namespace Uaflix if (init != null && init.rhub && rhub != -1) return TimeSpan.FromMinutes(rhub); - int ctime = AppInit.conf.mikrotik ? mikrotik : AppInit.conf.multiaccess ? init != null && init.cache_time > 0 ? init.cache_time : multiaccess : home; - if (init != null && ctime > init.cache_time && init.cache_time > 0) - ctime = init.cache_time; + int ctime = init != null && init.cache_time > 0 ? init.cache_time : multiaccess; + if (ctime > multiaccess) + ctime = multiaccess; return TimeSpan.FromMinutes(ctime); } diff --git a/Unimay/Controllers/Controller.cs b/Unimay/Controllers/Controller.cs index 5242090..0fe08ce 100644 --- a/Unimay/Controllers/Controller.cs +++ b/Unimay/Controllers/Controller.cs @@ -1,4 +1,3 @@ -using Shared.Engine; using System; using System.Threading.Tasks; using System.Linq; @@ -22,20 +21,20 @@ namespace Unimay.Controllers } [HttpGet] - [Route("unimay")] + [Route("lite/unimay")] async public ValueTask Index(string title, string original_title, string code, int serial = -1, int s = -1, int e = -1, bool play = false, bool rjson = false, bool checksearch = false) { await UpdateService.ConnectAsync(host); - var init = await loadKit(ModInit.Unimay); - if (await IsBadInitialization(init, rch: false)) + if (await IsRequestBlocked(rch: false)) return badInitMsg; - var invoke = new UnimayInvoke(init, hybridCache, OnLog, proxyManager); + var init = this.init; + var invoke = new UnimayInvoke(init, hybridCache, OnLog, proxyManager, httpHydra); if (checksearch) { - if (AppInit.conf?.online?.checkOnlineSearch != true) + if (!IsCheckOnlineSearchEnabled()) return OnError("unimay"); var searchResults = await invoke.Search(title, original_title, serial); @@ -169,5 +168,38 @@ namespace Unimay.Controllers cleaned = cleaned.Replace("?&", "?").Replace("&&", "&").TrimEnd('?', '&'); return cleaned; } + + private static bool IsCheckOnlineSearchEnabled() + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var checkProp = conf?.GetType().GetProperty("checkOnlineSearch", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (checkProp?.GetValue(conf) is bool enabled) + return enabled; + } + catch + { + } + + return true; + } + + private static void OnLog(string message) + { + System.Console.WriteLine(message); + } } } diff --git a/Unimay/GlobalUsings.cs b/Unimay/GlobalUsings.cs new file mode 100644 index 0000000..4c00409 --- /dev/null +++ b/Unimay/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Shared.Services; +global using Shared.Services.Hybrid; +global using Shared.Models.Base; +global using AppInit = Shared.CoreInit; diff --git a/Unimay/ModInit.cs b/Unimay/ModInit.cs index 7387c7f..d588e65 100644 --- a/Unimay/ModInit.cs +++ b/Unimay/ModInit.cs @@ -1,20 +1,10 @@ -using Newtonsoft.Json; -using Shared; -using Shared.Engine; -using Newtonsoft.Json.Linq; -using Shared; -using Shared.Models.Online.Settings; -using Shared.Models.Module; - -using Newtonsoft.Json; -using Shared; -using Shared.Engine; -using Newtonsoft.Json.Linq; using Microsoft.AspNetCore.Mvc; -using Microsoft.CodeAnalysis.Scripting; -using Microsoft.Extensions.Caching.Memory; -using Shared.Models; -using Shared.Models.Events; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Shared; +using Shared.Models.Module; +using Shared.Models.Module.Interfaces; +using Shared.Models.Online.Settings; using System; using System.Net.Http; using System.Net.Mime; @@ -28,9 +18,9 @@ using System.Threading.Tasks; namespace Unimay { - public class ModInit + public class ModInit : IModuleLoaded { - public static double Version => 3.4; + public static double Version => 4.0; public static OnlinesSettings Unimay; @@ -43,7 +33,7 @@ namespace Unimay /// /// модуль загружен /// - public static void loaded(InitspaceModel initspace) + public void Loaded(InitspaceModel initspace) { @@ -59,10 +49,48 @@ namespace Unimay list = new string[] { "socks5://IP:PORT" } } }; - Unimay = ModuleInvoke.Conf("Unimay", Unimay).ToObject(); + Unimay = ModuleInvoke.Init("Unimay", JObject.FromObject(Unimay)).ToObject(); // Виводити "уточнити пошук" - AppInit.conf.online.with_search.Add("unimay"); + RegisterWithSearch("unimay"); + } + + private static void RegisterWithSearch(string plugin) + { + try + { + var onlineType = Type.GetType("Online.ModInit"); + if (onlineType == null) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + onlineType = asm.GetType("Online.ModInit"); + if (onlineType != null) + break; + } + } + var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + var conf = confField?.GetValue(null); + var withSearchProp = conf?.GetType().GetProperty("with_search", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + + if (withSearchProp?.GetValue(conf) is System.Collections.IList list) + { + foreach (var item in list) + { + if (string.Equals(item?.ToString(), plugin, StringComparison.OrdinalIgnoreCase)) + return; + } + + list.Add(plugin); + } + } + catch + { + } + } + + public void Dispose() + { } } @@ -184,4 +212,4 @@ namespace Unimay } public record ConnectResponse(bool IsUpdateUnavailable, bool IsNoiseEnabled); -} \ No newline at end of file +} diff --git a/Unimay/OnlineApi.cs b/Unimay/OnlineApi.cs index 5468041..058adde 100644 --- a/Unimay/OnlineApi.cs +++ b/Unimay/OnlineApi.cs @@ -1,47 +1,46 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Shared.Models; -using Shared.Models.Base; using Shared.Models.Module; +using Shared.Models.Module.Interfaces; using System.Collections.Generic; +using System.Threading.Tasks; namespace Unimay { - public class OnlineApi + public class OnlineApi : IModuleOnline { - public static List<(string name, string url, string plugin, int index)> Invoke( - HttpContext httpContext, - IMemoryCache memoryCache, - RequestModel requestInfo, - string host, - OnlineEventsModel args) + public List Invoke(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) { long.TryParse(args.id, out long tmdbid); return Events(host, tmdbid, args.imdb_id, args.kinopoisk_id, args.title, args.original_title, args.original_language, args.year, args.source, args.serial, args.account_email); } - public static List<(string name, string url, string plugin, int index)> Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) + public Task> InvokeAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineEventsModel args) + => Task.FromResult(default(List)); + + public List Spider(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => null; + + public Task> SpiderAsync(HttpContext httpContext, IMemoryCache memoryCache, RequestModel requestInfo, string host, OnlineSpiderModel args) + => Task.FromResult(default(List)); + + private static List Events(string host, long id, string imdb_id, long kinopoisk_id, string title, string original_title, string original_language, int year, string source, int serial, string account_email) { - var online = new List<(string name, string url, string plugin, int index)>(); + var online = new List(); var init = ModInit.Unimay; - // Визначення isAnime згідно стандарту Lampac (Deepwiki): - // isanime = true якщо original_language == "ja" або "zh" bool hasLang = !string.IsNullOrEmpty(original_language); bool isanime = hasLang && (original_language == "ja" || original_language == "zh"); - // Unimay — аніме-провайдер. Додаємо якщо: - // - загальний пошук (serial == -1), або - // - контент є аніме (isanime), або - // - мова невідома (немає original_language) if (init.enable && !init.rip && (serial == -1 || isanime || !hasLang)) { string url = init.overridehost; if (string.IsNullOrEmpty(url) || UpdateService.IsDisconnected()) - url = $"{host}/unimay"; + url = $"{host}/lite/unimay"; - online.Add((init.displayname, url, "unimay", init.displayindex)); + online.Add(new ModuleOnlineItem(init.displayname, url, "unimay", init.displayindex)); } return online; diff --git a/Unimay/Unimay.csproj b/Unimay/Unimay.csproj index 9ced83e..c280999 100644 --- a/Unimay/Unimay.csproj +++ b/Unimay/Unimay.csproj @@ -1,11 +1,9 @@ - + - net8.0 - enable - enable - false - latest + net10.0 + library + true @@ -14,4 +12,4 @@ - \ No newline at end of file + diff --git a/Unimay/UnimayInvoke.cs b/Unimay/UnimayInvoke.cs index fc5ac65..e025f4b 100644 --- a/Unimay/UnimayInvoke.cs +++ b/Unimay/UnimayInvoke.cs @@ -6,7 +6,6 @@ using Shared.Models.Online.Settings; using Shared.Models; using System.Linq; using Unimay.Models; -using Shared.Engine; using System.Net; using System.Text; @@ -18,13 +17,15 @@ namespace Unimay private ProxyManager _proxyManager; private IHybridCache _hybridCache; private Action _onLog; + private readonly HttpHydra _httpHydra; - public UnimayInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager) + public UnimayInvoke(OnlinesSettings init, IHybridCache hybridCache, Action onLog, ProxyManager proxyManager, HttpHydra httpHydra = null) { _init = init; _hybridCache = hybridCache; _onLog = onLog; _proxyManager = proxyManager; + _httpHydra = httpHydra; } public async Task Search(string title, string original_title, int serial) @@ -39,7 +40,7 @@ namespace Unimay string searchUrl = $"{_init.host}/release/search?page=0&page_size=10&title={searchQuery}"; var headers = httpHeaders(_init); - SearchResponse root = await Http.Get(_init.cors(searchUrl), timeoutSeconds: 8, proxy: _proxyManager.Get(), headers: headers); + SearchResponse root = await HttpGet(searchUrl, headers, timeoutSeconds: 8); if (root == null || root.Content == null || root.Content.Count == 0) { @@ -69,7 +70,7 @@ namespace Unimay string releaseUrl = $"{_init.host}/release?code={code}"; var headers = httpHeaders(_init); - ReleaseResponse root = await Http.Get(_init.cors(releaseUrl), timeoutSeconds: 8, proxy: _proxyManager.Get(), headers: headers); + ReleaseResponse root = await HttpGet(releaseUrl, headers, timeoutSeconds: 8); if (root == null) { @@ -103,7 +104,7 @@ namespace Unimay } string itemTitle = item.Names?.Ukr ?? item.Names?.Eng ?? item.Title; - string releaseUrl = $"{host}/unimay?code={item.Code}&title={System.Web.HttpUtility.UrlEncode(itemTitle)}&original_title={System.Web.HttpUtility.UrlEncode(original_title ?? "")}&serial={serial}"; + string releaseUrl = $"{host}/lite/unimay?code={item.Code}&title={System.Web.HttpUtility.UrlEncode(itemTitle)}&original_title={System.Web.HttpUtility.UrlEncode(original_title ?? "")}&serial={serial}"; results.Add((itemTitle, item.Year, item.Type, releaseUrl)); } @@ -116,7 +117,7 @@ namespace Unimay return (null, null); var movieEpisode = releaseDetail.Playlist[0]; - string movieLink = $"{host}/unimay?code={releaseDetail.Code}&title={System.Web.HttpUtility.UrlEncode(title)}&original_title={System.Web.HttpUtility.UrlEncode(original_title ?? "")}&serial=0&play=true"; + string movieLink = $"{host}/lite/unimay?code={releaseDetail.Code}&title={System.Web.HttpUtility.UrlEncode(title)}&original_title={System.Web.HttpUtility.UrlEncode(original_title ?? "")}&serial=0&play=true"; string movieTitle = movieEpisode.Title ?? title; return (movieTitle, movieLink); @@ -124,7 +125,7 @@ namespace Unimay public (string seasonName, string seasonUrl, string seasonId) GetSeasonInfo(string host, string code, string title, string original_title) { - string seasonUrl = $"{host}/unimay?code={code}&title={System.Web.HttpUtility.UrlEncode(title)}&original_title={System.Web.HttpUtility.UrlEncode(original_title ?? "")}&serial=1&s=1"; + string seasonUrl = $"{host}/lite/unimay?code={code}&title={System.Web.HttpUtility.UrlEncode(title)}&original_title={System.Web.HttpUtility.UrlEncode(original_title ?? "")}&serial=1&s=1"; return ("Сезон 1", seasonUrl, "1"); } @@ -138,7 +139,7 @@ namespace Unimay foreach (var ep in releaseDetail.Playlist.Where(ep => ep.Number >= 1 && ep.Number <= 24).OrderBy(ep => ep.Number)) { string epTitle = ep.Title ?? $"Епізод {ep.Number}"; - string epLink = $"{host}/unimay?code={releaseDetail.Code}&title={System.Web.HttpUtility.UrlEncode(title)}&original_title={System.Web.HttpUtility.UrlEncode(original_title ?? "")}&serial=1&s=1&e={ep.Number}&play=true"; + string epLink = $"{host}/lite/unimay?code={releaseDetail.Code}&title={System.Web.HttpUtility.UrlEncode(title)}&original_title={System.Web.HttpUtility.UrlEncode(original_title ?? "")}&serial=1&s=1&e={ep.Number}&play=true"; episodes.Add((epTitle, epLink)); } @@ -160,12 +161,20 @@ namespace Unimay }; } + private Task HttpGet(string url, List headers, int timeoutSeconds = 15) + { + if (_httpHydra != null) + return _httpHydra.Get(url, newheaders: headers); + + return Http.Get(_init.cors(url), timeoutSeconds: timeoutSeconds, proxy: _proxyManager.Get(), headers: headers); + } + public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) { if (init != null && init.rhub && rhub != -1) return TimeSpan.FromMinutes(rhub); - int ctime = AppInit.conf.mikrotik ? mikrotik : AppInit.conf.multiaccess ? init != null && init.cache_time > 0 ? init.cache_time : multiaccess : home; + int ctime = init != null && init.cache_time > 0 ? init.cache_time : multiaccess; if (ctime > multiaccess) ctime = multiaccess;