mirror of
https://github.com/lampame/lampac-ukraine.git
synced 2026-04-16 09:22:21 +00:00
refactor: Remove KlonFUN integration and Wormhole enrichment, simplifying play source resolution to only use Wormhole.
This commit is contained in:
parent
6cdddcbf30
commit
ae39beb8b6
@ -45,25 +45,10 @@ namespace Makhno
|
||||
|
||||
var invoke = new MakhnoInvoke(init, hybridCache, OnLog, proxyManager);
|
||||
|
||||
var resolved = await ResolvePlaySource(imdb_id, title, original_title, year, serial, invoke);
|
||||
var resolved = await ResolvePlaySource(imdb_id, serial, invoke);
|
||||
if (resolved == null || string.IsNullOrEmpty(resolved.PlayUrl))
|
||||
return OnError();
|
||||
|
||||
if (resolved.ShouldEnrich)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await EnrichWormhole(imdb_id, year, resolved, invoke);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnLog($"Makhno wormhole enrich failed: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (resolved.IsSerial)
|
||||
return await HandleSerial(resolved.PlayUrl, imdb_id, title, original_title, year, t, season, rjson, invoke);
|
||||
|
||||
@ -84,7 +69,7 @@ namespace Makhno
|
||||
OnLog($"Makhno Play: {title} (s={s}, season={season}, t={t}, episodeId={episodeId}) play={play}");
|
||||
|
||||
var invoke = new MakhnoInvoke(init, hybridCache, OnLog, proxyManager);
|
||||
var resolved = await ResolvePlaySource(imdb_id, title, original_title, year, serial: 1, invoke);
|
||||
var resolved = await ResolvePlaySource(imdb_id, serial: 1, invoke);
|
||||
if (resolved == null || string.IsNullOrEmpty(resolved.PlayUrl))
|
||||
return OnError();
|
||||
|
||||
@ -142,7 +127,7 @@ namespace Makhno
|
||||
OnLog($"Makhno PlayMovie: {title} ({year}) play={play}");
|
||||
|
||||
var invoke = new MakhnoInvoke(init, hybridCache, OnLog, proxyManager);
|
||||
var resolved = await ResolvePlaySource(imdb_id, title, original_title, year, serial: 0, invoke);
|
||||
var resolved = await ResolvePlaySource(imdb_id, serial: 0, invoke);
|
||||
if (resolved == null || string.IsNullOrEmpty(resolved.PlayUrl))
|
||||
return OnError();
|
||||
|
||||
@ -455,68 +440,24 @@ namespace Makhno
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<ResolveResult> ResolvePlaySource(string imdbId, string title, string originalTitle, int year, int serial, MakhnoInvoke invoke)
|
||||
private async Task<ResolveResult> ResolvePlaySource(string imdbId, int serial, MakhnoInvoke invoke)
|
||||
{
|
||||
string playUrl = null;
|
||||
if (string.IsNullOrWhiteSpace(imdbId))
|
||||
return null;
|
||||
|
||||
if (!string.IsNullOrEmpty(imdbId))
|
||||
string cacheKey = $"makhno:wormhole:{imdbId}";
|
||||
string playUrl = await InvokeCache<string>(cacheKey, TimeSpan.FromMinutes(5), async () =>
|
||||
{
|
||||
string cacheKey = $"makhno:wormhole:{imdbId}";
|
||||
playUrl = await InvokeCache<string>(cacheKey, TimeSpan.FromMinutes(5), async () =>
|
||||
{
|
||||
return await invoke.GetWormholePlay(imdbId);
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty(playUrl))
|
||||
{
|
||||
return new ResolveResult
|
||||
{
|
||||
PlayUrl = playUrl,
|
||||
IsSerial = IsSerialByUrl(playUrl, serial),
|
||||
ShouldEnrich = false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
string searchQuery = originalTitle ?? title;
|
||||
string klonSearchCacheKey = $"makhno:klonfun:search:{imdbId ?? searchQuery}";
|
||||
var klonSearchResults = await InvokeCache<List<KlonSearchResult>>(klonSearchCacheKey, TimeSpan.FromMinutes(10), async () =>
|
||||
{
|
||||
return await invoke.SearchKlonFUN(imdbId, title, originalTitle);
|
||||
return await invoke.GetWormholePlay(imdbId);
|
||||
});
|
||||
|
||||
if (klonSearchResults != null && klonSearchResults.Count > 0)
|
||||
if (!string.IsNullOrEmpty(playUrl))
|
||||
{
|
||||
var klonSelected = invoke.SelectKlonFUNItem(klonSearchResults, year > 0 ? year : null, title, originalTitle);
|
||||
if (klonSelected != null && !string.IsNullOrWhiteSpace(klonSelected.Url))
|
||||
return new ResolveResult
|
||||
{
|
||||
string klonPlayerCacheKey = $"makhno:klonfun:player:{klonSelected.Url}";
|
||||
string klonPlayerUrl = await InvokeCache<string>(klonPlayerCacheKey, TimeSpan.FromMinutes(10), async () =>
|
||||
{
|
||||
return await invoke.GetKlonFUNPlayerUrl(klonSelected.Url);
|
||||
});
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(klonPlayerUrl))
|
||||
{
|
||||
string klonAshdiPath = invoke.ExtractAshdiPath(klonPlayerUrl);
|
||||
|
||||
return new ResolveResult
|
||||
{
|
||||
PlayUrl = klonPlayerUrl,
|
||||
AshdiPath = klonAshdiPath,
|
||||
Selected = new SearchResult
|
||||
{
|
||||
ImdbId = imdbId,
|
||||
Title = klonSelected.Title,
|
||||
TitleEn = originalTitle,
|
||||
Year = klonSelected.Year > 0 ? klonSelected.Year.ToString() : null,
|
||||
Category = invoke.IsSerialPlayerUrl(klonPlayerUrl) ? "Серіал" : "Фільм"
|
||||
},
|
||||
IsSerial = serial == 1 || invoke.IsSerialPlayerUrl(klonPlayerUrl) || IsSerialByUrl(klonPlayerUrl, serial),
|
||||
ShouldEnrich = !string.IsNullOrWhiteSpace(klonAshdiPath)
|
||||
};
|
||||
}
|
||||
}
|
||||
PlayUrl = playUrl,
|
||||
IsSerial = IsSerialByUrl(playUrl, serial)
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -533,38 +474,6 @@ namespace Makhno
|
||||
return url.Contains("/serial/", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private async Task EnrichWormhole(string imdbId, int year, ResolveResult resolved, MakhnoInvoke invoke)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(imdbId) || resolved == null || string.IsNullOrWhiteSpace(resolved.AshdiPath))
|
||||
return;
|
||||
|
||||
int? yearValue = year > 0 ? year : null;
|
||||
if (!yearValue.HasValue && int.TryParse(resolved.Selected?.Year, out int parsedYear))
|
||||
yearValue = parsedYear;
|
||||
|
||||
var tmdbResult = await invoke.FetchTmdbByImdb(imdbId, yearValue, resolved.IsSerial);
|
||||
if (tmdbResult == null)
|
||||
return;
|
||||
|
||||
var (item, _) = tmdbResult.Value;
|
||||
var tmdbId = item.Value<long?>("id");
|
||||
if (!tmdbId.HasValue)
|
||||
return;
|
||||
|
||||
string mediaType = resolved.IsSerial ? "tv" : "movie";
|
||||
int serialValue = resolved.IsSerial ? 1 : 0;
|
||||
|
||||
var payload = new
|
||||
{
|
||||
imdb_id = imdbId,
|
||||
_id = $"{mediaType}:{tmdbId.Value}",
|
||||
serial = serialValue,
|
||||
ashdi = resolved.AshdiPath
|
||||
};
|
||||
|
||||
await invoke.PostWormholeAsync(payload);
|
||||
}
|
||||
|
||||
private static string StripLampacArgs(string url)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
@ -606,10 +515,7 @@ namespace Makhno
|
||||
private class ResolveResult
|
||||
{
|
||||
public string PlayUrl { get; set; }
|
||||
public string AshdiPath { get; set; }
|
||||
public SearchResult Selected { get; set; }
|
||||
public bool IsSerial { get; set; }
|
||||
public bool ShouldEnrich { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,10 +2,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using HtmlAgilityPack;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Shared;
|
||||
@ -19,11 +17,8 @@ namespace Makhno
|
||||
public class MakhnoInvoke
|
||||
{
|
||||
private const string WormholeHost = "https://wh.lme.isroot.in/";
|
||||
private const string AshdiHost = "https://ashdi.vip";
|
||||
private const string KlonHost = "https://klon.fun";
|
||||
private static readonly Regex Quality4kRegex = new Regex(@"(^|[^0-9])(2160p?)([^0-9]|$)|\b4k\b|\buhd\b", RegexOptions.IgnoreCase);
|
||||
private static readonly Regex QualityFhdRegex = new Regex(@"(^|[^0-9])(1080p?)([^0-9]|$)|\bfhd\b", RegexOptions.IgnoreCase);
|
||||
private static readonly Regex YearRegex = new Regex(@"(19|20)\d{2}", RegexOptions.IgnoreCase);
|
||||
|
||||
private readonly OnlinesSettings _init;
|
||||
private readonly IHybridCache _hybridCache;
|
||||
@ -65,284 +60,6 @@ namespace Makhno
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<KlonSearchResult>> SearchKlonFUN(string imdbId, string title, string originalTitle)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(imdbId))
|
||||
{
|
||||
var byImdb = await SearchKlonFUNByQuery(imdbId);
|
||||
if (byImdb?.Count > 0)
|
||||
{
|
||||
_onLog($"Makhno KlonFUN: знайдено {byImdb.Count} результат(ів) за imdb_id={imdbId}");
|
||||
return byImdb;
|
||||
}
|
||||
}
|
||||
|
||||
var queries = new[] { originalTitle, title }
|
||||
.Where(q => !string.IsNullOrWhiteSpace(q))
|
||||
.Select(q => q.Trim())
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var results = new List<KlonSearchResult>();
|
||||
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (string query in queries)
|
||||
{
|
||||
var partial = await SearchKlonFUNByQuery(query);
|
||||
if (partial == null || partial.Count == 0)
|
||||
continue;
|
||||
|
||||
foreach (var item in partial)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item?.Url) && seen.Add(item.Url))
|
||||
results.Add(item);
|
||||
}
|
||||
|
||||
if (results.Count > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (results.Count > 0)
|
||||
{
|
||||
_onLog($"Makhno KlonFUN: знайдено {results.Count} результат(ів) за назвою");
|
||||
return results;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_onLog($"Makhno KlonFUN: помилка пошуку - {ex.Message}");
|
||||
}
|
||||
|
||||
return new List<KlonSearchResult>();
|
||||
}
|
||||
|
||||
public KlonSearchResult SelectKlonFUNItem(List<KlonSearchResult> items, int? year, string title, string titleEn)
|
||||
{
|
||||
if (items == null || items.Count == 0)
|
||||
return null;
|
||||
|
||||
if (items.Count == 1)
|
||||
return items[0];
|
||||
|
||||
var byYearAndTitle = items
|
||||
.Where(item => YearMatch(item, year) && TitleMatch(item?.Title, title, titleEn))
|
||||
.ToList();
|
||||
|
||||
if (byYearAndTitle.Count == 1)
|
||||
return byYearAndTitle[0];
|
||||
if (byYearAndTitle.Count > 1)
|
||||
return null;
|
||||
|
||||
var byTitle = items
|
||||
.Where(item => TitleMatch(item?.Title, title, titleEn))
|
||||
.ToList();
|
||||
|
||||
if (byTitle.Count == 1)
|
||||
return byTitle[0];
|
||||
if (byTitle.Count > 1)
|
||||
return null;
|
||||
|
||||
var byYear = items
|
||||
.Where(item => YearMatch(item, year))
|
||||
.ToList();
|
||||
|
||||
if (byYear.Count == 1)
|
||||
return byYear[0];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<string> GetKlonFUNPlayerUrl(string itemUrl)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(itemUrl))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var headers = new List<HeadersModel>()
|
||||
{
|
||||
new HeadersModel("User-Agent", Http.UserAgent),
|
||||
new HeadersModel("Referer", KlonHost)
|
||||
};
|
||||
|
||||
string html = await Http.Get(_init.cors(itemUrl), headers: headers, proxy: _proxyManager.Get());
|
||||
if (string.IsNullOrWhiteSpace(html))
|
||||
return null;
|
||||
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(html);
|
||||
|
||||
string playerUrl = doc.DocumentNode
|
||||
.SelectSingleNode("//div[contains(@class,'film-player')]//iframe")
|
||||
?.GetAttributeValue("data-src", null);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(playerUrl))
|
||||
{
|
||||
playerUrl = doc.DocumentNode
|
||||
.SelectSingleNode("//div[contains(@class,'film-player')]//iframe")
|
||||
?.GetAttributeValue("src", null);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(playerUrl))
|
||||
{
|
||||
playerUrl = doc.DocumentNode
|
||||
.SelectSingleNode("//iframe[contains(@src,'ashdi.vip') or contains(@src,'zetvideo.net') or contains(@src,'/vod/') or contains(@src,'/serial/')]")
|
||||
?.GetAttributeValue("src", null);
|
||||
}
|
||||
|
||||
return NormalizeUrl(KlonHost, playerUrl);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_onLog($"Makhno KlonFUN: помилка отримання плеєра - {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSerialPlayerUrl(string playerUrl)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(playerUrl)
|
||||
&& playerUrl.IndexOf("/serial/", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private async Task<List<KlonSearchResult>> SearchKlonFUNByQuery(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var headers = new List<HeadersModel>()
|
||||
{
|
||||
new HeadersModel("User-Agent", Http.UserAgent),
|
||||
new HeadersModel("Referer", KlonHost)
|
||||
};
|
||||
|
||||
string form = $"do=search&subaction=search&story={WebUtility.UrlEncode(query)}";
|
||||
string html = await Http.Post(_init.cors(KlonHost), form, headers: headers, proxy: _proxyManager.Get());
|
||||
if (string.IsNullOrWhiteSpace(html))
|
||||
return null;
|
||||
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(html);
|
||||
|
||||
var results = new List<KlonSearchResult>();
|
||||
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var nodes = doc.DocumentNode.SelectNodes("//div[contains(@class,'short-news__slide-item')]");
|
||||
if (nodes != null)
|
||||
{
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
string href = node.SelectSingleNode(".//a[contains(@class,'short-news__small-card__link')]")
|
||||
?.GetAttributeValue("href", null)
|
||||
?? node.SelectSingleNode(".//a[contains(@class,'card-link__style')]")
|
||||
?.GetAttributeValue("href", null);
|
||||
|
||||
href = NormalizeUrl(KlonHost, href);
|
||||
if (string.IsNullOrWhiteSpace(href) || !seen.Add(href))
|
||||
continue;
|
||||
|
||||
string itemTitle = CleanText(node.SelectSingleNode(".//div[contains(@class,'card-link__text')]")?.InnerText);
|
||||
if (string.IsNullOrWhiteSpace(itemTitle))
|
||||
{
|
||||
itemTitle = CleanText(node.SelectSingleNode(".//a[contains(@class,'card-link__style')]")?.InnerText);
|
||||
}
|
||||
|
||||
string poster = node.SelectSingleNode(".//img[contains(@class,'card-poster__img')]")
|
||||
?.GetAttributeValue("data-src", null);
|
||||
if (string.IsNullOrWhiteSpace(poster))
|
||||
{
|
||||
poster = node.SelectSingleNode(".//img[contains(@class,'card-poster__img')]")
|
||||
?.GetAttributeValue("src", null);
|
||||
}
|
||||
|
||||
string meta = CleanText(node.SelectSingleNode(".//div[contains(@class,'subscribe-label-module')]")?.InnerText);
|
||||
int itemYear = 0;
|
||||
if (!string.IsNullOrWhiteSpace(meta))
|
||||
{
|
||||
var yearMatch = YearRegex.Match(meta);
|
||||
if (yearMatch.Success)
|
||||
int.TryParse(yearMatch.Value, out itemYear);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(itemTitle))
|
||||
continue;
|
||||
|
||||
results.Add(new KlonSearchResult
|
||||
{
|
||||
Title = itemTitle,
|
||||
Url = href,
|
||||
Poster = NormalizeUrl(KlonHost, poster),
|
||||
Year = itemYear
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (results.Count == 0)
|
||||
{
|
||||
var anchors = doc.DocumentNode.SelectNodes("//a[.//span[contains(@class,'searchheading')]]");
|
||||
if (anchors != null)
|
||||
{
|
||||
foreach (var anchor in anchors)
|
||||
{
|
||||
string href = NormalizeUrl(KlonHost, anchor.GetAttributeValue("href", null));
|
||||
if (string.IsNullOrWhiteSpace(href) || !seen.Add(href))
|
||||
continue;
|
||||
|
||||
string itemTitle = CleanText(anchor.SelectSingleNode(".//span[contains(@class,'searchheading')]")?.InnerText);
|
||||
if (string.IsNullOrWhiteSpace(itemTitle))
|
||||
continue;
|
||||
|
||||
results.Add(new KlonSearchResult
|
||||
{
|
||||
Title = itemTitle,
|
||||
Url = href,
|
||||
Poster = string.Empty,
|
||||
Year = 0
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_onLog($"Makhno KlonFUN: помилка запиту '{query}' - {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static string NormalizeUrl(string host, string url)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
return string.Empty;
|
||||
|
||||
string value = WebUtility.HtmlDecode(url.Trim());
|
||||
|
||||
if (value.StartsWith("//"))
|
||||
return $"https:{value}";
|
||||
|
||||
if (value.StartsWith("/"))
|
||||
return host.TrimEnd('/') + value;
|
||||
|
||||
if (!value.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
||||
return host.TrimEnd('/') + "/" + value.TrimStart('/');
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static string CleanText(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
return string.Empty;
|
||||
|
||||
return HtmlEntity.DeEntitize(value).Trim();
|
||||
}
|
||||
|
||||
public async Task<PlayerData> GetPlayerData(string playerUrl)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerUrl))
|
||||
@ -809,157 +526,6 @@ namespace Makhno
|
||||
return normalized;
|
||||
}
|
||||
|
||||
public string ExtractAshdiPath(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
return null;
|
||||
|
||||
var match = Regex.Match(value, @"https?://(?:www\.)?ashdi\.vip/((?:vod|serial)/\d+)", RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
return match.Groups[1].Value;
|
||||
|
||||
match = Regex.Match(value, @"\b((?:vod|serial)/\d+)\b", RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
return match.Groups[1].Value;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string BuildAshdiUrl(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return null;
|
||||
|
||||
if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
||||
return path;
|
||||
|
||||
return $"{AshdiHost}/{path.TrimStart('/')}";
|
||||
}
|
||||
|
||||
private bool YearMatch(KlonSearchResult item, int? year)
|
||||
{
|
||||
if (year == null || item == null || item.Year <= 0)
|
||||
return false;
|
||||
|
||||
return item.Year == year.Value;
|
||||
}
|
||||
|
||||
private bool TitleMatch(string itemTitle, string title, string titleEn)
|
||||
{
|
||||
return TitleMatch(itemTitle, null, title, titleEn);
|
||||
}
|
||||
|
||||
private bool TitleMatch(string itemTitleRaw, string itemTitleEnRaw, string title, string titleEn)
|
||||
{
|
||||
string itemTitle = NormalizeTitle(itemTitleRaw);
|
||||
string itemTitleEn = NormalizeTitle(itemTitleEnRaw);
|
||||
string targetTitle = NormalizeTitle(title);
|
||||
string targetTitleEn = NormalizeTitle(titleEn);
|
||||
|
||||
return (itemTitle.Length > 0 && targetTitle.Length > 0 && itemTitle == targetTitle)
|
||||
|| (itemTitle.Length > 0 && targetTitleEn.Length > 0 && itemTitle == targetTitleEn)
|
||||
|| (itemTitleEn.Length > 0 && targetTitle.Length > 0 && itemTitleEn == targetTitle)
|
||||
|| (itemTitleEn.Length > 0 && targetTitleEn.Length > 0 && itemTitleEn == targetTitleEn);
|
||||
}
|
||||
|
||||
private string NormalizeTitle(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
return string.Empty;
|
||||
|
||||
string text = value.ToLowerInvariant();
|
||||
text = Regex.Replace(text, @"[^\w\s]+", " ");
|
||||
text = Regex.Replace(text, @"\b(season|сезон|частина|part|ova|special|movie|film)\b", " ");
|
||||
text = Regex.Replace(text, @"\b(\d+)(st|nd|rd|th)\b", "$1");
|
||||
text = Regex.Replace(text, @"\b\d+\b", " ");
|
||||
text = Regex.Replace(text, @"\s+", " ");
|
||||
return text.Trim();
|
||||
}
|
||||
|
||||
public async Task<(JObject item, string mediaType)?> FetchTmdbByImdb(string imdbId, int? year, bool isSerial)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(imdbId))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
string apiKey = AppInit.conf?.tmdb?.api_key;
|
||||
if (string.IsNullOrWhiteSpace(apiKey))
|
||||
return null;
|
||||
|
||||
string tmdbUrl = $"http://{AppInit.conf.listen.localhost}:{AppInit.conf.listen.port}/tmdb/api/3/find/{imdbId}?external_source=imdb_id&api_key={apiKey}&language=en-US";
|
||||
|
||||
var headers = new List<HeadersModel>()
|
||||
{
|
||||
new HeadersModel("User-Agent", Http.UserAgent)
|
||||
};
|
||||
|
||||
JObject payload = await Http.Get<JObject>(tmdbUrl, timeoutSeconds: 6, headers: headers);
|
||||
if (payload == null)
|
||||
return null;
|
||||
|
||||
var movieResults = payload["movie_results"] as JArray ?? new JArray();
|
||||
var tvResults = payload["tv_results"] as JArray ?? new JArray();
|
||||
|
||||
var candidates = new List<(JObject item, string mediaType)>();
|
||||
foreach (var item in movieResults.OfType<JObject>())
|
||||
candidates.Add((item, "movie"));
|
||||
foreach (var item in tvResults.OfType<JObject>())
|
||||
candidates.Add((item, "tv"));
|
||||
|
||||
if (candidates.Count == 0)
|
||||
return null;
|
||||
|
||||
string preferredMediaType = isSerial ? "tv" : "movie";
|
||||
var orderedCandidates = candidates
|
||||
.Where(c => c.mediaType == preferredMediaType)
|
||||
.Concat(candidates.Where(c => c.mediaType != preferredMediaType))
|
||||
.ToList();
|
||||
|
||||
if (year.HasValue)
|
||||
{
|
||||
string yearText = year.Value.ToString();
|
||||
foreach (var candidate in orderedCandidates)
|
||||
{
|
||||
string dateValue = candidate.mediaType == "movie"
|
||||
? candidate.item.Value<string>("release_date")
|
||||
: candidate.item.Value<string>("first_air_date");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(dateValue) && dateValue.StartsWith(yearText, StringComparison.Ordinal))
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return orderedCandidates[0];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_onLog($"Makhno TMDB fetch failed: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> PostWormholeAsync(object payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
var headers = new List<HeadersModel>()
|
||||
{
|
||||
new HeadersModel("Content-Type", "application/json"),
|
||||
new HeadersModel("User-Agent", Http.UserAgent)
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(payload, Formatting.None);
|
||||
await Http.Post(_init.cors(WormholeHost), json, timeoutSeconds: 6, headers: headers, proxy: _proxyManager.Get());
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_onLog($"Makhno wormhole insert failed: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class WormholeResponse
|
||||
{
|
||||
public string play { get; set; }
|
||||
|
||||
@ -1,43 +1,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Makhno.Models
|
||||
{
|
||||
public class SearchResult
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonProperty("imdb_id")]
|
||||
public string ImdbId { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("title_alt")]
|
||||
public string TitleAlt { get; set; }
|
||||
|
||||
[JsonProperty("title_en")]
|
||||
public string TitleEn { get; set; }
|
||||
|
||||
[JsonProperty("title_ru")]
|
||||
public string TitleRu { get; set; }
|
||||
|
||||
[JsonProperty("year")]
|
||||
public string Year { get; set; }
|
||||
|
||||
[JsonProperty("category")]
|
||||
public string Category { get; set; }
|
||||
}
|
||||
|
||||
public class KlonSearchResult
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string Poster { get; set; }
|
||||
public int Year { get; set; }
|
||||
}
|
||||
|
||||
public class PlayerData
|
||||
{
|
||||
public string File { get; set; }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user