mirror of
https://github.com/lampame/lampac-ukraine.git
synced 2026-06-17 12:08:54 +00:00
Move the foreach loop inside the null/empty check for ashdiStreams to ensure proper iteration only when streams are available. This improves code readability and prevents potential issues with iterating over null or empty collections.
537 lines
25 KiB
C#
537 lines
25 KiB
C#
using System.Text.Json;
|
|
using Shared.Engine;
|
|
using System;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using System.Collections.Generic;
|
|
using System.Web;
|
|
using System.Linq;
|
|
using Shared;
|
|
using Shared.Models.Templates;
|
|
using LME.AnimeON.Models;
|
|
using System.Text.RegularExpressions;
|
|
using System.Text;
|
|
using Shared.Models.Online.Settings;
|
|
using Shared.Models;
|
|
using HtmlAgilityPack;
|
|
|
|
namespace LME.AnimeON.Controllers
|
|
{
|
|
public class Controller : BaseOnlineController
|
|
{
|
|
ProxyManager proxyManager;
|
|
|
|
public Controller() : base(ModInit.Settings)
|
|
{
|
|
proxyManager = new ProxyManager(ModInit.AnimeON);
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("lite/lme_animeon")]
|
|
async public Task<ActionResult> 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 = loadKit(ModInit.AnimeON);
|
|
if (!init.enable)
|
|
return Forbid();
|
|
|
|
TryEnableMagicApn(init);
|
|
var invoke = new AnimeONInvoke(init, hybridCache, OnLog, proxyManager, httpHydra);
|
|
|
|
if (checksearch)
|
|
{
|
|
if (!IsCheckOnlineSearchEnabled())
|
|
return OnError("lme_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("lme_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}");
|
|
|
|
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("lme_animeon", refresh_proxy: true);
|
|
|
|
// [Refactoring] Використовується агрегована структура (AggregateSerialStructure) — попередній збір allOptions не потрібний
|
|
|
|
// [Refactoring] Перевірка allOptions видалена — використовується перевірка структури озвучок нижче
|
|
|
|
if (serial == 1)
|
|
{
|
|
if (s == -1) // Крок 1: Вибір аніме (як сезони)
|
|
{
|
|
var seasonItems = seasons
|
|
.Select((anime, index) => new
|
|
{
|
|
Anime = anime,
|
|
Index = index,
|
|
SeasonNumber = anime.Season > 0 ? anime.Season : index + 1
|
|
})
|
|
.GroupBy(x => x.SeasonNumber)
|
|
.Select(g => g.First())
|
|
.OrderBy(x => x.SeasonNumber)
|
|
.ToList();
|
|
|
|
var season_tpl = new SeasonTpl(seasonItems.Count);
|
|
foreach (var item in seasonItems)
|
|
{
|
|
string seasonName = item.SeasonNumber.ToString();
|
|
string link = $"{host}/lite/lme_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}");
|
|
return rjson ? Content(season_tpl.ToJson(), "application/json; charset=utf-8") : Content(season_tpl.ToHtml(), "text/html; charset=utf-8");
|
|
}
|
|
else // Крок 2/3: Вибір озвучки та епізодів
|
|
{
|
|
var seasonItems = seasons
|
|
.Select((anime, index) => new
|
|
{
|
|
Anime = anime,
|
|
Index = index,
|
|
SeasonNumber = anime.Season > 0 ? anime.Season : index + 1
|
|
})
|
|
.GroupBy(x => x.SeasonNumber)
|
|
.Select(g => g.First())
|
|
.OrderBy(x => x.SeasonNumber)
|
|
.ToList();
|
|
|
|
var selected = seasonItems.FirstOrDefault(x => x.SeasonNumber == s);
|
|
if (selected == null && s >= 0 && s < seasons.Count)
|
|
selected = new { Anime = seasons[s], Index = s, SeasonNumber = seasons[s].Season > 0 ? seasons[s].Season : s + 1 };
|
|
|
|
if (selected == null)
|
|
return OnError("lme_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("lme_animeon", refresh_proxy: true);
|
|
|
|
OnLog($"AnimeON: voices found = {structure.Voices.Count}");
|
|
var voiceItems = structure.Voices
|
|
.Select(v =>
|
|
{
|
|
string display = v.Value?.DisplayName;
|
|
if (string.IsNullOrWhiteSpace(display))
|
|
display = v.Key;
|
|
if (string.IsNullOrWhiteSpace(display))
|
|
display = "Озвучка";
|
|
return new { Key = v.Key, Display = display };
|
|
})
|
|
.ToList();
|
|
|
|
// Автовибір першої озвучки якщо t не задано
|
|
if (string.IsNullOrEmpty(t))
|
|
t = voiceItems.First().Key;
|
|
|
|
// Формуємо список озвучок
|
|
var voice_tpl = new VoiceTpl();
|
|
foreach (var voice in voiceItems)
|
|
{
|
|
string voiceLink = $"{host}/lite/lme_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("lme_animeon", refresh_proxy: true);
|
|
|
|
var episode_tpl = new EpisodeTpl();
|
|
var selectedVoiceInfo = structure.Voices[t];
|
|
|
|
// Формуємо епізоди для вибраної озвучки
|
|
foreach (var ep in selectedVoiceInfo.Episodes.OrderBy(e => e.Number))
|
|
{
|
|
string episodeName = !string.IsNullOrEmpty(ep.Title) ? ep.Title : $"Епізод {ep.Number}";
|
|
string seasonStr = selectedSeasonNumber.ToString();
|
|
string episodeStr = ep.Number.ToString();
|
|
|
|
// Для серіалів пріоритет — готовий fileUrl з API episodes (без додаткового резолву).
|
|
if (!string.IsNullOrEmpty(ep.Hls))
|
|
{
|
|
List<HeadersModel> streamHeaders = null;
|
|
bool forceProxy = false;
|
|
if (ep.Hls.Contains("ashdi.vip", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
streamHeaders = new List<HeadersModel>()
|
|
{
|
|
new HeadersModel("User-Agent", "Mozilla/5.0"),
|
|
new HeadersModel("Referer", "https://ashdi.vip/")
|
|
};
|
|
forceProxy = true;
|
|
}
|
|
|
|
string readyStreamUrl = BuildStreamUrl(init, ep.Hls, streamHeaders, forceProxy);
|
|
episode_tpl.Append(episodeName, title ?? original_title, seasonStr, episodeStr, readyStreamUrl);
|
|
continue;
|
|
}
|
|
|
|
string streamLink = ep.VideoUrl;
|
|
bool needsResolve = selectedVoiceInfo.PlayerType == "moon" || selectedVoiceInfo.PlayerType == "ashdi";
|
|
|
|
if (string.IsNullOrEmpty(streamLink) && ep.EpisodeId > 0)
|
|
{
|
|
string callUrl = $"{host}/lite/lme_animeon/play?episode_id={ep.EpisodeId}&serial=1";
|
|
episode_tpl.Append(episodeName, title ?? original_title, seasonStr, episodeStr, accsArgs(callUrl), "call");
|
|
continue;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(streamLink))
|
|
continue;
|
|
|
|
if (needsResolve || streamLink.Contains("moonanime.art") || streamLink.Contains("ashdi.vip/vod"))
|
|
{
|
|
string callUrl = $"{host}/lite/lme_animeon/play?url={HttpUtility.UrlEncode(streamLink)}&serial=1";
|
|
episode_tpl.Append(episodeName, title ?? original_title, seasonStr, episodeStr, accsArgs(callUrl), "call");
|
|
}
|
|
else
|
|
{
|
|
string playUrl = BuildStreamUrl(init, streamLink, headers: null, forceProxy: false);
|
|
episode_tpl.Append(episodeName, title ?? original_title, seasonStr, episodeStr, playUrl);
|
|
}
|
|
}
|
|
|
|
// Повертаємо озвучки + епізоди разом
|
|
OnLog($"AnimeON: return episodes count={selectedVoiceInfo.Episodes.Count} for voice='{t}' season={selectedAnime.Season}");
|
|
episode_tpl.Append(voice_tpl);
|
|
if (rjson)
|
|
return Content(episode_tpl.ToJson(), "application/json; charset=utf-8");
|
|
|
|
return Content(episode_tpl.ToHtml(), "text/html; charset=utf-8");
|
|
}
|
|
}
|
|
else // Фільм
|
|
{
|
|
var firstAnime = seasons.FirstOrDefault();
|
|
if (firstAnime == null)
|
|
return OnError("lme_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("lme_animeon", refresh_proxy: true);
|
|
|
|
var tpl = new MovieTpl(title, original_title);
|
|
|
|
foreach (var fundub in fundubs)
|
|
{
|
|
if (fundub?.Fundub == null || fundub.Player == null || fundub.Player.Count == 0)
|
|
continue;
|
|
|
|
foreach (var player in fundub.Player)
|
|
{
|
|
var episodesData = await invoke.GetEpisodes(firstAnime.Id, player.Id, fundub.Fundub.Id);
|
|
if (episodesData == null || episodesData.Episodes == null || episodesData.Episodes.Count == 0)
|
|
continue;
|
|
|
|
var firstEp = episodesData.Episodes.FirstOrDefault();
|
|
if (firstEp == null)
|
|
continue;
|
|
|
|
string streamLink = !string.IsNullOrEmpty(firstEp.Hls) ? firstEp.Hls : firstEp.VideoUrl;
|
|
if (string.IsNullOrEmpty(streamLink))
|
|
continue;
|
|
|
|
string translationName = $"[{player.Name}] {fundub.Fundub.Name}";
|
|
|
|
bool needsResolve = player.Name?.ToLower() == "moon" || player.Name?.ToLower() == "ashdi";
|
|
if (streamLink.Contains("ashdi.vip/vod", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var ashdiStreams = await invoke.ParseAshdiPageStreams(streamLink);
|
|
if (ashdiStreams != null && ashdiStreams.Count > 0)
|
|
{
|
|
foreach (var ashdiStream in ashdiStreams)
|
|
{
|
|
string optionName = $"{translationName} {ashdiStream.Title}";
|
|
string subtitlesParam = ashdiStream.Subtitles != null ? $"&subtitles={HttpUtility.UrlEncode(JsonSerializer.Serialize(ashdiStream.Subtitles.ToObject()))}" : string.Empty;
|
|
string callUrl = $"{host}/lite/lme_animeon/play?url={HttpUtility.UrlEncode(ashdiStream.Link)}{subtitlesParam}";
|
|
tpl.Append(optionName, accsArgs(callUrl), "call");
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (needsResolve || streamLink.Contains("moonanime.art/iframe/") || streamLink.Contains("ashdi.vip/vod"))
|
|
{
|
|
string callUrl = $"{host}/lite/lme_animeon/play?url={HttpUtility.UrlEncode(streamLink)}";
|
|
tpl.Append(translationName, accsArgs(callUrl), "call");
|
|
}
|
|
else
|
|
{
|
|
tpl.Append(translationName, BuildStreamUrl(init, streamLink, headers: null, forceProxy: false));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Якщо не зібрали жодної опції — повертаємо помилку
|
|
if (tpl.data == null || tpl.data.Count == 0)
|
|
return OnError("lme_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");
|
|
}
|
|
}
|
|
|
|
async Task<List<FundubModel>> GetFundubs(OnlinesSettings init, int animeId)
|
|
{
|
|
string fundubsUrl = $"{init.host}/api/player/{animeId}/translations";
|
|
|
|
string fundubsJson = await httpHydra.Get(fundubsUrl, newheaders: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) });
|
|
if (string.IsNullOrEmpty(fundubsJson))
|
|
return null;
|
|
|
|
var fundubsResponse = JsonSerializer.Deserialize<FundubsResponseModel>(fundubsJson);
|
|
if (fundubsResponse?.Translations == null || fundubsResponse.Translations.Count == 0)
|
|
return null;
|
|
|
|
var fundubs = new List<FundubModel>();
|
|
foreach (var translation in fundubsResponse.Translations)
|
|
{
|
|
var fundubModel = new FundubModel
|
|
{
|
|
Fundub = translation.Translation,
|
|
Player = translation.Player
|
|
};
|
|
fundubs.Add(fundubModel);
|
|
}
|
|
return fundubs;
|
|
}
|
|
|
|
async Task<EpisodeModel> GetEpisodes(OnlinesSettings init, int animeId, int playerId, int fundubId)
|
|
{
|
|
string episodesUrl = $"{init.host}/api/player/{animeId}/episodes?take=100&skip=-1&playerId={playerId}&translationId={fundubId}";
|
|
|
|
string episodesJson = await httpHydra.Get(episodesUrl, newheaders: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) });
|
|
if (string.IsNullOrEmpty(episodesJson))
|
|
return null;
|
|
|
|
return JsonSerializer.Deserialize<EpisodeModel>(episodesJson);
|
|
}
|
|
|
|
async ValueTask<List<SearchModel>> search(OnlinesSettings init, string imdb_id, long kinopoisk_id, string title, string original_title, int year)
|
|
{
|
|
string memKey = $"AnimeON:search:{kinopoisk_id}:{imdb_id}";
|
|
if (hybridCache.TryGetValue(memKey, out List<SearchModel> res))
|
|
return res;
|
|
|
|
try
|
|
{
|
|
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) };
|
|
|
|
async Task<List<SearchModel>> FindAnime(string query)
|
|
{
|
|
if (string.IsNullOrEmpty(query))
|
|
return null;
|
|
|
|
string searchUrl = $"{init.host}/api/anime/search?text={HttpUtility.UrlEncode(query)}";
|
|
|
|
string searchJson = await httpHydra.Get(searchUrl, newheaders: headers);
|
|
if (string.IsNullOrEmpty(searchJson))
|
|
return null;
|
|
|
|
var searchResponse = JsonSerializer.Deserialize<SearchResponseModel>(searchJson);
|
|
return searchResponse?.Result;
|
|
}
|
|
|
|
var searchResults = await FindAnime(title) ?? await FindAnime(original_title);
|
|
if (searchResults == null)
|
|
return null;
|
|
|
|
if (!string.IsNullOrEmpty(imdb_id))
|
|
{
|
|
var seasons = searchResults.Where(a => a.ImdbId == imdb_id).ToList();
|
|
if (seasons.Count > 0)
|
|
{
|
|
hybridCache.Set(memKey, seasons, cacheTime(5));
|
|
return seasons;
|
|
}
|
|
}
|
|
|
|
// Fallback to first result if no imdb match
|
|
var firstResult = searchResults.FirstOrDefault();
|
|
if (firstResult != null)
|
|
{
|
|
var list = new List<SearchModel> { firstResult };
|
|
hybridCache.Set(memKey, list, cacheTime(5));
|
|
return list;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
OnLog($"AnimeON error: {ex.Message}");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
[HttpGet("lite/lme_animeon/play")]
|
|
public async Task<ActionResult> Play(string url, int episode_id = 0, string title = null, int serial = 0, string subtitles = null)
|
|
{
|
|
await UpdateService.ConnectAsync(host);
|
|
|
|
var init = loadKit(ModInit.AnimeON);
|
|
if (!init.enable)
|
|
return Forbid();
|
|
|
|
TryEnableMagicApn(init);
|
|
var invoke = new AnimeONInvoke(init, hybridCache, OnLog, proxyManager, httpHydra);
|
|
bool disableAshdiMultivoiceForVod = serial == 1;
|
|
OnLog($"AnimeON Play: url={url}, episode_id={episode_id}, serial={serial}");
|
|
|
|
string streamLink = null;
|
|
if (episode_id > 0)
|
|
{
|
|
streamLink = await invoke.ResolveEpisodeStream(episode_id, disableAshdiMultivoiceForVod);
|
|
}
|
|
else if (!string.IsNullOrEmpty(url))
|
|
{
|
|
streamLink = await invoke.ResolveVideoUrl(url, disableAshdiMultivoiceForVod);
|
|
}
|
|
else
|
|
{
|
|
OnLog("AnimeON Play: empty url");
|
|
return OnError("lme_animeon", refresh_proxy: true);
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(streamLink))
|
|
{
|
|
OnLog("AnimeON Play: cannot extract stream");
|
|
return OnError("lme_animeon", refresh_proxy: true);
|
|
}
|
|
|
|
List<HeadersModel> streamHeaders = null;
|
|
bool forceProxy = false;
|
|
if (streamLink.Contains("ashdi.vip", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
streamHeaders = new List<HeadersModel>()
|
|
{
|
|
new HeadersModel("User-Agent", "Mozilla/5.0"),
|
|
new HeadersModel("Referer", "https://ashdi.vip/")
|
|
};
|
|
forceProxy = true;
|
|
}
|
|
|
|
SubtitleTpl subtitleTpl = null;
|
|
if (!string.IsNullOrEmpty(subtitles))
|
|
{
|
|
try
|
|
{
|
|
var subtitleDtos = JsonSerializer.Deserialize<List<SubtitleDto>>(subtitles);
|
|
if (subtitleDtos != null && subtitleDtos.Count > 0)
|
|
{
|
|
subtitleTpl = new SubtitleTpl(subtitleDtos.Count);
|
|
foreach (var sub in subtitleDtos)
|
|
subtitleTpl.Append(sub.label, sub.url);
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
string streamUrl = BuildStreamUrl(init, streamLink, streamHeaders, forceProxy);
|
|
OnLog("AnimeON Play: return call JSON");
|
|
return UpdateService.Validate(Content(VideoTpl.ToJson("play", streamUrl, title ?? string.Empty, subtitles: subtitleTpl), "application/json; charset=utf-8"));
|
|
}
|
|
|
|
private static string StripLampacArgs(string url)
|
|
{
|
|
if (string.IsNullOrEmpty(url))
|
|
return url;
|
|
|
|
string cleaned = System.Text.RegularExpressions.Regex.Replace(
|
|
url,
|
|
@"([?&])(account_email|uid|nws_id)=[^&]*",
|
|
"$1",
|
|
System.Text.RegularExpressions.RegexOptions.IgnoreCase
|
|
);
|
|
|
|
cleaned = cleaned.Replace("?&", "?").Replace("&&", "&").TrimEnd('?', '&');
|
|
return cleaned;
|
|
}
|
|
|
|
string BuildStreamUrl(OnlinesSettings init, string streamLink, List<HeadersModel> headers, bool forceProxy)
|
|
{
|
|
string link = streamLink?.Trim();
|
|
if (string.IsNullOrEmpty(link))
|
|
return link;
|
|
|
|
link = StripLampacArgs(link);
|
|
|
|
if (ApnHelper.IsEnabled(init))
|
|
{
|
|
if (ModInit.ApnHostProvided || ApnHelper.IsAshdiUrl(link))
|
|
return ApnHelper.WrapUrl(init, link);
|
|
|
|
var noApn = (OnlinesSettings)init.Clone();
|
|
noApn.apnstream = false;
|
|
noApn.apn = null;
|
|
return HostStreamProxy(noApn, link, headers: headers, force_streamproxy: forceProxy);
|
|
}
|
|
|
|
return HostStreamProxy(init, link, headers: headers, force_streamproxy: forceProxy);
|
|
}
|
|
|
|
private void TryEnableMagicApn(OnlinesSettings init)
|
|
{
|
|
if (init == null
|
|
|| init.apn != null
|
|
|| init.streamproxy
|
|
|| string.IsNullOrWhiteSpace(ModInit.MagicApnAshdiHost))
|
|
return;
|
|
|
|
string player = new RchClient(HttpContext, host, init, requestInfo).InfoConnected()?.player;
|
|
bool useInnerPlayer = string.IsNullOrWhiteSpace(player)
|
|
|| player.Equals("inner", StringComparison.OrdinalIgnoreCase);
|
|
if (!useInnerPlayer)
|
|
return;
|
|
|
|
ApnHelper.ApplyInitConf(true, ModInit.MagicApnAshdiHost, init);
|
|
OnLog($"AnimeON: увімкнено magic_apn для Ashdi (player={player ?? "unknown"}).");
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|