mirror of
https://github.com/lampame/lampac-ukraine.git
synced 2026-04-16 09:22:21 +00:00
Integrate a new online streaming source for UafilmME, including API invocation, search, and playback functionality. Adds APN proxy helper for Ashdi streams, module initialization, and related models and controllers to extend the existing online framework.
752 lines
26 KiB
C#
752 lines
26 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
using System.Web;
|
|
using Shared;
|
|
using Shared.Engine;
|
|
using Shared.Models;
|
|
using Shared.Models.Online.Settings;
|
|
using UafilmME.Models;
|
|
|
|
namespace UafilmME
|
|
{
|
|
public class UafilmMEInvoke
|
|
{
|
|
private readonly OnlinesSettings _init;
|
|
private readonly IHybridCache _hybridCache;
|
|
private readonly Action<string> _onLog;
|
|
private readonly ProxyManager _proxyManager;
|
|
private readonly HttpHydra _httpHydra;
|
|
|
|
|
|
|
|
public UafilmMEInvoke(OnlinesSettings init, IHybridCache hybridCache, Action<string> onLog, ProxyManager proxyManager, HttpHydra httpHydra = null)
|
|
{
|
|
_init = init;
|
|
_hybridCache = hybridCache;
|
|
_onLog = onLog;
|
|
_proxyManager = proxyManager;
|
|
_httpHydra = httpHydra;
|
|
}
|
|
|
|
public async Task<List<UafilmSearchItem>> Search(string title, string originalTitle, int year)
|
|
{
|
|
var queries = BuildSearchQueries(title, originalTitle, year).ToList();
|
|
if (queries.Count == 0)
|
|
return new List<UafilmSearchItem>();
|
|
|
|
var all = new Dictionary<long, UafilmSearchItem>();
|
|
foreach (var query in queries)
|
|
{
|
|
var items = await SearchByQuery(query);
|
|
foreach (var item in items)
|
|
all[item.Id] = item;
|
|
}
|
|
|
|
return all.Values.ToList();
|
|
}
|
|
|
|
public UafilmSearchItem SelectBestSearchResult(List<UafilmSearchItem> results, long tmdbId, string imdbId, string title, string originalTitle, int year, int serial)
|
|
{
|
|
if (results == null || results.Count == 0)
|
|
return null;
|
|
|
|
foreach (var item in results)
|
|
item.MatchScore = CalcMatchScore(item, tmdbId, imdbId, title, originalTitle, year, serial);
|
|
|
|
return results
|
|
.OrderByDescending(r => r.MatchScore)
|
|
.ThenByDescending(r => r.Year)
|
|
.FirstOrDefault();
|
|
}
|
|
|
|
public async Task<UafilmTitleDetails> GetTitleDetails(long titleId)
|
|
{
|
|
string memKey = $"UafilmME:title:{titleId}";
|
|
if (_hybridCache.TryGetValue(memKey, out UafilmTitleDetails cached))
|
|
return cached;
|
|
|
|
try
|
|
{
|
|
string json = await ApiGet($"titles/{titleId}?loader=titlePage", $"{_init.host}/titles/{titleId}");
|
|
var title = ParseTitleDetails(json);
|
|
if (title != null)
|
|
_hybridCache.Set(memKey, title, cacheTime(30, init: _init));
|
|
|
|
return title;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_onLog?.Invoke($"UafilmME: помилка отримання title {titleId}: {ex.Message}");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public async Task<List<UafilmSeasonItem>> GetAllSeasons(long titleId)
|
|
{
|
|
string memKey = $"UafilmME:seasons:{titleId}";
|
|
if (_hybridCache.TryGetValue(memKey, out List<UafilmSeasonItem> cached))
|
|
return cached;
|
|
|
|
var all = new List<UafilmSeasonItem>();
|
|
int currentPage = 1;
|
|
int guard = 0;
|
|
|
|
while (currentPage > 0 && guard < 100)
|
|
{
|
|
guard++;
|
|
var page = await GetSeasonsPage(titleId, currentPage);
|
|
if (page.Items.Count == 0)
|
|
break;
|
|
|
|
all.AddRange(page.Items);
|
|
|
|
if (page.NextPage.HasValue && page.NextPage.Value != currentPage)
|
|
currentPage = page.NextPage.Value;
|
|
else
|
|
break;
|
|
}
|
|
|
|
var result = all
|
|
.GroupBy(s => s.Number)
|
|
.Select(g => g.OrderByDescending(x => x.EpisodesCount).First())
|
|
.OrderBy(s => s.Number)
|
|
.ToList();
|
|
|
|
if (result.Count == 0)
|
|
{
|
|
var title = await GetTitleDetails(titleId);
|
|
if (title?.SeasonsCount > 0)
|
|
{
|
|
for (int i = 1; i <= title.SeasonsCount; i++)
|
|
{
|
|
result.Add(new UafilmSeasonItem()
|
|
{
|
|
Number = i,
|
|
EpisodesCount = 0
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result.Count > 0)
|
|
_hybridCache.Set(memKey, result, cacheTime(60, init: _init));
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<List<UafilmEpisodeItem>> GetSeasonEpisodes(long titleId, int season)
|
|
{
|
|
string memKey = $"UafilmME:episodes:{titleId}:{season}";
|
|
if (_hybridCache.TryGetValue(memKey, out List<UafilmEpisodeItem> cached))
|
|
return cached;
|
|
|
|
var all = new List<UafilmEpisodeItem>();
|
|
int currentPage = 1;
|
|
int guard = 0;
|
|
|
|
while (currentPage > 0 && guard < 200)
|
|
{
|
|
guard++;
|
|
var page = await GetEpisodesPage(titleId, season, currentPage);
|
|
if (page.Items.Count == 0)
|
|
break;
|
|
|
|
all.AddRange(page.Items);
|
|
|
|
if (page.NextPage.HasValue && page.NextPage.Value != currentPage)
|
|
currentPage = page.NextPage.Value;
|
|
else
|
|
break;
|
|
}
|
|
|
|
var result = all
|
|
.GroupBy(e => e.Id)
|
|
.Select(g => g.First())
|
|
.OrderBy(e => e.EpisodeNumber)
|
|
.ToList();
|
|
|
|
if (result.Count > 0)
|
|
_hybridCache.Set(memKey, result, cacheTime(30, init: _init));
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<List<UafilmVideoItem>> GetMovieVideos(long titleId)
|
|
{
|
|
var title = await GetTitleDetails(titleId);
|
|
if (title == null || title.PrimaryVideoId <= 0)
|
|
return new List<UafilmVideoItem>();
|
|
|
|
var watch = await GetWatch(title.PrimaryVideoId);
|
|
return CollectPlayableVideos(watch);
|
|
}
|
|
|
|
public async Task<UafilmWatchInfo> GetWatch(long videoId)
|
|
{
|
|
if (videoId <= 0)
|
|
return null;
|
|
|
|
string memKey = $"UafilmME:watch:{videoId}";
|
|
if (_hybridCache.TryGetValue(memKey, out UafilmWatchInfo cached))
|
|
return cached;
|
|
|
|
try
|
|
{
|
|
string json = await ApiGet($"watch/{videoId}", _init.host);
|
|
var watch = ParseWatchInfo(json);
|
|
if (watch?.Video != null)
|
|
_hybridCache.Set(memKey, watch, cacheTime(7, init: _init));
|
|
|
|
return watch;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_onLog?.Invoke($"UafilmME: помилка отримання watch/{videoId}: {ex.Message}");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public List<UafilmVideoItem> CollectPlayableVideos(UafilmWatchInfo watch)
|
|
{
|
|
var list = new List<UafilmVideoItem>();
|
|
if (watch == null)
|
|
return list;
|
|
|
|
if (watch.Video != null)
|
|
list.Add(watch.Video);
|
|
|
|
if (watch.AlternativeVideos != null && watch.AlternativeVideos.Count > 0)
|
|
list.AddRange(watch.AlternativeVideos);
|
|
|
|
return list
|
|
.Where(v => v != null && v.Id > 0)
|
|
.Select(v =>
|
|
{
|
|
v.Src = NormalizeVideoSource(v.Src);
|
|
return v;
|
|
})
|
|
.Where(v => !string.IsNullOrWhiteSpace(v.Src))
|
|
.Where(v => !string.Equals(v.Type, "embed", StringComparison.OrdinalIgnoreCase))
|
|
.Where(v => v.Src.IndexOf("youtube.com", StringComparison.OrdinalIgnoreCase) < 0)
|
|
.GroupBy(v => v.Id)
|
|
.Select(g => g.First())
|
|
.ToList();
|
|
}
|
|
|
|
private async Task<List<UafilmSearchItem>> SearchByQuery(string query)
|
|
{
|
|
string memKey = $"UafilmME:search:{query}";
|
|
if (_hybridCache.TryGetValue(memKey, out List<UafilmSearchItem> cached))
|
|
return cached;
|
|
|
|
string encoded = HttpUtility.UrlEncode(query);
|
|
string json = await ApiGet($"search/{encoded}?loader=searchPage", $"{_init.host}/search/{encoded}");
|
|
var items = ParseSearchResults(json);
|
|
|
|
if (items.Count > 0)
|
|
_hybridCache.Set(memKey, items, cacheTime(20, init: _init));
|
|
|
|
return items;
|
|
}
|
|
|
|
private async Task<(List<UafilmSeasonItem> Items, int? NextPage)> GetSeasonsPage(long titleId, int page)
|
|
{
|
|
string memKey = $"UafilmME:seasons-page:{titleId}:{page}";
|
|
if (_hybridCache.TryGetValue(memKey, out List<UafilmSeasonItem> cachedItems) &&
|
|
_hybridCache.TryGetValue(memKey + ":next", out int? cachedNext))
|
|
{
|
|
return (cachedItems, cachedNext);
|
|
}
|
|
|
|
string suffix = page > 1 ? $"?page={page}" : string.Empty;
|
|
string json = await ApiGet($"titles/{titleId}/seasons{suffix}", $"{_init.host}/titles/{titleId}");
|
|
var parsed = ParseSeasonsPage(json);
|
|
|
|
_hybridCache.Set(memKey, parsed.Items, cacheTime(30, init: _init));
|
|
_hybridCache.Set(memKey + ":next", parsed.NextPage, cacheTime(30, init: _init));
|
|
return parsed;
|
|
}
|
|
|
|
private async Task<(List<UafilmEpisodeItem> Items, int? NextPage)> GetEpisodesPage(long titleId, int season, int page)
|
|
{
|
|
string memKey = $"UafilmME:episodes-page:{titleId}:{season}:{page}";
|
|
if (_hybridCache.TryGetValue(memKey, out List<UafilmEpisodeItem> cachedItems) &&
|
|
_hybridCache.TryGetValue(memKey + ":next", out int? cachedNext))
|
|
{
|
|
return (cachedItems, cachedNext);
|
|
}
|
|
|
|
string suffix = page > 1 ? $"?page={page}" : string.Empty;
|
|
string json = await ApiGet($"titles/{titleId}/seasons/{season}/episodes{suffix}", $"{_init.host}/titles/{titleId}");
|
|
var parsed = ParseEpisodesPage(json);
|
|
|
|
_hybridCache.Set(memKey, parsed.Items, cacheTime(20, init: _init));
|
|
_hybridCache.Set(memKey + ":next", parsed.NextPage, cacheTime(20, init: _init));
|
|
return parsed;
|
|
}
|
|
|
|
private async Task<string> ApiGet(string pathAndQuery, string referer)
|
|
{
|
|
string url = $"{_init.host.TrimEnd('/')}/api/v1/{pathAndQuery.TrimStart('/')}";
|
|
string reqReferer = string.IsNullOrWhiteSpace(referer) ? $"{_init.host}/" : referer;
|
|
|
|
var headers = new List<HeadersModel>()
|
|
{
|
|
new HeadersModel("User-Agent", "EchoapiRuntime/1.1.0"),
|
|
new HeadersModel("Referer", reqReferer),
|
|
new HeadersModel("Accept", "*/*")
|
|
};
|
|
|
|
if (_httpHydra != null)
|
|
return await _httpHydra.Get(url, newheaders: headers);
|
|
|
|
return await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
|
|
}
|
|
|
|
private string NormalizeVideoSource(string src)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(src))
|
|
return null;
|
|
|
|
src = src.Trim();
|
|
if (src.StartsWith("//"))
|
|
return "https:" + src;
|
|
|
|
if (src.StartsWith("/"))
|
|
return _init.host.TrimEnd('/') + src;
|
|
|
|
return src;
|
|
}
|
|
|
|
private static IEnumerable<string> BuildSearchQueries(string title, string originalTitle, int year)
|
|
{
|
|
var queries = new List<string>();
|
|
void Add(string value)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(value))
|
|
queries.Add(value.Trim());
|
|
}
|
|
|
|
Add(title);
|
|
Add(originalTitle);
|
|
|
|
if (year > 1900)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(title))
|
|
Add($"{title} {year}");
|
|
|
|
if (!string.IsNullOrWhiteSpace(originalTitle))
|
|
Add($"{originalTitle} {year}");
|
|
}
|
|
|
|
return queries
|
|
.Where(q => !string.IsNullOrWhiteSpace(q))
|
|
.Distinct(StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
|
|
private List<UafilmSearchItem> ParseSearchResults(string json)
|
|
{
|
|
var list = new List<UafilmSearchItem>();
|
|
if (string.IsNullOrWhiteSpace(json))
|
|
return list;
|
|
|
|
using var doc = JsonDocument.Parse(json);
|
|
if (!TryGetArray(doc.RootElement, "results", out var results))
|
|
return list;
|
|
|
|
foreach (var item in results.EnumerateArray())
|
|
{
|
|
if (!TryReadLong(item, "id", out long id) || id <= 0)
|
|
continue;
|
|
|
|
list.Add(new UafilmSearchItem()
|
|
{
|
|
Id = id,
|
|
Name = ReadString(item, "name"),
|
|
OriginalTitle = ReadString(item, "original_title"),
|
|
IsSeries = ReadBool(item, "is_series"),
|
|
Year = ReadInt(item, "year"),
|
|
ImdbId = ReadString(item, "imdb_id"),
|
|
TmdbId = ReadLong(item, "tmdb_id"),
|
|
Poster = ReadString(item, "poster")
|
|
});
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
private UafilmTitleDetails ParseTitleDetails(string json)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(json))
|
|
return null;
|
|
|
|
using var doc = JsonDocument.Parse(json);
|
|
if (!TryGetObject(doc.RootElement, "title", out var titleObj))
|
|
return null;
|
|
|
|
var info = new UafilmTitleDetails()
|
|
{
|
|
Id = ReadLong(titleObj, "id"),
|
|
Name = ReadString(titleObj, "name"),
|
|
OriginalTitle = ReadString(titleObj, "original_title"),
|
|
IsSeries = ReadBool(titleObj, "is_series"),
|
|
Year = ReadInt(titleObj, "year"),
|
|
ImdbId = ReadString(titleObj, "imdb_id"),
|
|
TmdbId = ReadLong(titleObj, "tmdb_id"),
|
|
SeasonsCount = ReadInt(titleObj, "seasons_count")
|
|
};
|
|
|
|
if (TryGetObject(titleObj, "primary_video", out var primaryVideo))
|
|
info.PrimaryVideoId = ReadLong(primaryVideo, "id");
|
|
|
|
return info;
|
|
}
|
|
|
|
private (List<UafilmSeasonItem> Items, int? NextPage) ParseSeasonsPage(string json)
|
|
{
|
|
var items = new List<UafilmSeasonItem>();
|
|
int? next = null;
|
|
if (string.IsNullOrWhiteSpace(json))
|
|
return (items, next);
|
|
|
|
using var doc = JsonDocument.Parse(json);
|
|
if (!TryGetObject(doc.RootElement, "pagination", out var pagination))
|
|
return (items, next);
|
|
|
|
next = ReadNullableInt(pagination, "next_page");
|
|
|
|
if (!TryGetArray(pagination, "data", out var data))
|
|
return (items, next);
|
|
|
|
foreach (var item in data.EnumerateArray())
|
|
{
|
|
int number = ReadInt(item, "number");
|
|
if (number <= 0)
|
|
continue;
|
|
|
|
items.Add(new UafilmSeasonItem()
|
|
{
|
|
Id = ReadLong(item, "id"),
|
|
Number = number,
|
|
EpisodesCount = ReadInt(item, "episodes_count")
|
|
});
|
|
}
|
|
|
|
return (items, next);
|
|
}
|
|
|
|
private (List<UafilmEpisodeItem> Items, int? NextPage) ParseEpisodesPage(string json)
|
|
{
|
|
var items = new List<UafilmEpisodeItem>();
|
|
int? next = null;
|
|
if (string.IsNullOrWhiteSpace(json))
|
|
return (items, next);
|
|
|
|
using var doc = JsonDocument.Parse(json);
|
|
if (!TryGetObject(doc.RootElement, "pagination", out var pagination))
|
|
return (items, next);
|
|
|
|
next = ReadNullableInt(pagination, "next_page");
|
|
|
|
if (!TryGetArray(pagination, "data", out var data))
|
|
return (items, next);
|
|
|
|
foreach (var item in data.EnumerateArray())
|
|
{
|
|
long episodeId = ReadLong(item, "id");
|
|
if (episodeId <= 0)
|
|
continue;
|
|
|
|
long primaryVideoId = 0;
|
|
string primaryVideoName = null;
|
|
if (TryGetObject(item, "primary_video", out var primaryVideoObj))
|
|
{
|
|
primaryVideoId = ReadLong(primaryVideoObj, "id");
|
|
primaryVideoName = ReadString(primaryVideoObj, "name");
|
|
}
|
|
|
|
items.Add(new UafilmEpisodeItem()
|
|
{
|
|
Id = episodeId,
|
|
Name = ReadString(item, "name"),
|
|
SeasonNumber = ReadInt(item, "season_number"),
|
|
EpisodeNumber = ReadInt(item, "episode_number"),
|
|
PrimaryVideoId = primaryVideoId,
|
|
PrimaryVideoName = primaryVideoName
|
|
});
|
|
}
|
|
|
|
return (items, next);
|
|
}
|
|
|
|
private UafilmWatchInfo ParseWatchInfo(string json)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(json))
|
|
return null;
|
|
|
|
using var doc = JsonDocument.Parse(json);
|
|
if (doc.RootElement.ValueKind != JsonValueKind.Object)
|
|
return null;
|
|
|
|
var watch = new UafilmWatchInfo();
|
|
|
|
if (TryGetObject(doc.RootElement, "video", out var videoObj))
|
|
watch.Video = ParseVideo(videoObj);
|
|
|
|
if (TryGetArray(doc.RootElement, "alternative_videos", out var alternatives))
|
|
{
|
|
foreach (var alt in alternatives.EnumerateArray())
|
|
{
|
|
var parsed = ParseVideo(alt);
|
|
if (parsed != null)
|
|
watch.AlternativeVideos.Add(parsed);
|
|
}
|
|
}
|
|
|
|
return watch;
|
|
}
|
|
|
|
private static UafilmVideoItem ParseVideo(JsonElement obj)
|
|
{
|
|
long id = ReadLong(obj, "id");
|
|
if (id <= 0)
|
|
return null;
|
|
|
|
return new UafilmVideoItem()
|
|
{
|
|
Id = id,
|
|
Name = ReadString(obj, "name"),
|
|
Src = ReadString(obj, "src"),
|
|
Type = ReadString(obj, "type"),
|
|
Quality = ReadString(obj, "quality"),
|
|
Origin = ReadString(obj, "origin"),
|
|
Language = ReadString(obj, "language"),
|
|
SeasonNum = ReadNullableInt(obj, "season_num"),
|
|
EpisodeNum = ReadNullableInt(obj, "episode_num"),
|
|
EpisodeId = ReadLong(obj, "episode_id")
|
|
};
|
|
}
|
|
|
|
private int CalcMatchScore(UafilmSearchItem item, long tmdbId, string imdbId, string title, string originalTitle, int year, int serial)
|
|
{
|
|
int score = 0;
|
|
|
|
if (item == null)
|
|
return score;
|
|
|
|
if (tmdbId > 0 && item.TmdbId == tmdbId)
|
|
score += 120;
|
|
|
|
if (!string.IsNullOrWhiteSpace(imdbId) && !string.IsNullOrWhiteSpace(item.ImdbId) && string.Equals(item.ImdbId.Trim(), imdbId.Trim(), StringComparison.OrdinalIgnoreCase))
|
|
score += 120;
|
|
|
|
if (serial == 1)
|
|
score += item.IsSeries ? 25 : -25;
|
|
else
|
|
score += item.IsSeries ? -15 : 15;
|
|
|
|
if (year > 1900 && item.Year > 1900)
|
|
{
|
|
int diff = Math.Abs(item.Year - year);
|
|
if (diff == 0)
|
|
score += 20;
|
|
else if (diff == 1)
|
|
score += 10;
|
|
else if (diff == 2)
|
|
score += 5;
|
|
else
|
|
score -= 6;
|
|
}
|
|
|
|
score += ScoreTitle(item.Name, title);
|
|
score += ScoreTitle(item.Name, originalTitle);
|
|
score += ScoreTitle(item.OriginalTitle, title);
|
|
score += ScoreTitle(item.OriginalTitle, originalTitle);
|
|
|
|
return score;
|
|
}
|
|
|
|
private static int ScoreTitle(string candidate, string expected)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(candidate) || string.IsNullOrWhiteSpace(expected))
|
|
return 0;
|
|
|
|
string left = NormalizeTitle(candidate);
|
|
string right = NormalizeTitle(expected);
|
|
if (string.IsNullOrEmpty(left) || string.IsNullOrEmpty(right))
|
|
return 0;
|
|
|
|
if (left == right)
|
|
return 35;
|
|
|
|
if (left.Contains(right) || right.Contains(left))
|
|
return 20;
|
|
|
|
var leftWords = left.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
|
var rightWords = right.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
|
int overlap = leftWords.Intersect(rightWords).Count();
|
|
if (overlap >= 2)
|
|
return 12;
|
|
if (overlap == 1)
|
|
return 6;
|
|
|
|
return 0;
|
|
}
|
|
|
|
private static string NormalizeTitle(string value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
return string.Empty;
|
|
|
|
string normalized = value.ToLowerInvariant();
|
|
normalized = Regex.Replace(normalized, "[^\\p{L}\\p{Nd}]+", " ", RegexOptions.CultureInvariant);
|
|
normalized = Regex.Replace(normalized, "\\s+", " ", RegexOptions.CultureInvariant).Trim();
|
|
return normalized;
|
|
}
|
|
|
|
private static bool TryGetObject(JsonElement source, string property, out JsonElement value)
|
|
{
|
|
value = default;
|
|
if (!source.TryGetProperty(property, out var prop) || prop.ValueKind != JsonValueKind.Object)
|
|
return false;
|
|
|
|
value = prop;
|
|
return true;
|
|
}
|
|
|
|
private static bool TryGetArray(JsonElement source, string property, out JsonElement value)
|
|
{
|
|
value = default;
|
|
if (!source.TryGetProperty(property, out var prop) || prop.ValueKind != JsonValueKind.Array)
|
|
return false;
|
|
|
|
value = prop;
|
|
return true;
|
|
}
|
|
|
|
private static string ReadString(JsonElement source, string property)
|
|
{
|
|
if (!source.TryGetProperty(property, out var value))
|
|
return null;
|
|
|
|
if (value.ValueKind == JsonValueKind.String)
|
|
return value.GetString();
|
|
|
|
if (value.ValueKind == JsonValueKind.Number)
|
|
return value.GetRawText();
|
|
|
|
if (value.ValueKind == JsonValueKind.True)
|
|
return bool.TrueString;
|
|
|
|
if (value.ValueKind == JsonValueKind.False)
|
|
return bool.FalseString;
|
|
|
|
return null;
|
|
}
|
|
|
|
private static bool ReadBool(JsonElement source, string property)
|
|
{
|
|
if (!source.TryGetProperty(property, out var value))
|
|
return false;
|
|
|
|
if (value.ValueKind == JsonValueKind.True)
|
|
return true;
|
|
|
|
if (value.ValueKind == JsonValueKind.False)
|
|
return false;
|
|
|
|
if (value.ValueKind == JsonValueKind.Number)
|
|
return value.GetInt32() != 0;
|
|
|
|
if (value.ValueKind == JsonValueKind.String)
|
|
{
|
|
string text = value.GetString();
|
|
if (bool.TryParse(text, out bool parsedBool))
|
|
return parsedBool;
|
|
|
|
if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out int parsedInt))
|
|
return parsedInt != 0;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static int ReadInt(JsonElement source, string property)
|
|
{
|
|
if (!source.TryGetProperty(property, out var value))
|
|
return 0;
|
|
|
|
if (value.ValueKind == JsonValueKind.Number && value.TryGetInt32(out int number))
|
|
return number;
|
|
|
|
if (value.ValueKind == JsonValueKind.String && int.TryParse(value.GetString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out int parsed))
|
|
return parsed;
|
|
|
|
return 0;
|
|
}
|
|
|
|
private static int? ReadNullableInt(JsonElement source, string property)
|
|
{
|
|
if (!source.TryGetProperty(property, out var value))
|
|
return null;
|
|
|
|
if (value.ValueKind == JsonValueKind.Null)
|
|
return null;
|
|
|
|
if (value.ValueKind == JsonValueKind.Number && value.TryGetInt32(out int number))
|
|
return number;
|
|
|
|
if (value.ValueKind == JsonValueKind.String && int.TryParse(value.GetString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out int parsed))
|
|
return parsed;
|
|
|
|
return null;
|
|
}
|
|
|
|
private static long ReadLong(JsonElement source, string property)
|
|
{
|
|
return TryReadLong(source, property, out long value)
|
|
? value
|
|
: 0;
|
|
}
|
|
|
|
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 = init != null && init.cache_time > 0 ? init.cache_time : multiaccess;
|
|
|
|
if (ctime > multiaccess)
|
|
ctime = multiaccess;
|
|
|
|
return TimeSpan.FromMinutes(ctime);
|
|
}
|
|
|
|
private static bool TryReadLong(JsonElement source, string property, out long value)
|
|
{
|
|
value = 0;
|
|
if (!source.TryGetProperty(property, out var element))
|
|
return false;
|
|
|
|
if (element.ValueKind == JsonValueKind.Number && element.TryGetInt64(out long number))
|
|
{
|
|
value = number;
|
|
return true;
|
|
}
|
|
|
|
if (element.ValueKind == JsonValueKind.String && long.TryParse(element.GetString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out long parsed))
|
|
{
|
|
value = parsed;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|