lampac/Online/Controllers/Anime/Animebesst.cs
lampac-talks f843f04fd4 chore: initial commit 154.3
Signed-off-by: lampac-talks <lampac-talks@users.noreply.github.com>
2026-01-30 16:23:09 +03:00

208 lines
8.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.AspNetCore.Mvc;
using Shared.Engine.RxEnumerate;
namespace Online.Controllers
{
public class Animebesst : BaseOnlineController
{
public Animebesst() : base(AppInit.conf.Animebesst) { }
[HttpGet]
[Route("lite/animebesst")]
async public Task<ActionResult> Index(string title, string uri, int s, bool rjson = false, bool similar = false)
{
if (await IsRequestBlocked(rch: true))
return badInitMsg;
rhubFallback:
if (string.IsNullOrEmpty(uri))
{
if (string.IsNullOrWhiteSpace(title))
return OnError();
#region Поиск
var cache = await InvokeCacheResult<List<(string title, string year, string uri, string s, string img)>>($"animebesst:search:{title}", 40, async e =>
{
bool reqOk = false;
List<(string title, string year, string uri, string s, string img)> catalog = null;
string data = $"do=search&subaction=search&search_start=0&full_search=0&result_from=1&story={HttpUtility.UrlEncode(title)}";
await httpHydra.PostSpan($"{init.corsHost()}/index.php?do=search", data, search =>
{
reqOk = search.Contains(">Поиск по сайту<", StringComparison.OrdinalIgnoreCase);
var sidebar = Rx.Split("id=\"sidebar\"", search);
if (sidebar.Count == 0)
return;
var rx = Rx.Split("class=\"shortstory-listab\"", sidebar[0].Span, 1);
if (rx.Count == 0)
return;
catalog = new List<(string title, string year, string uri, string s, string img)>(rx.Count);
foreach (var row in rx.Rows())
{
if (row.Contains("Новости"))
continue;
var g = row.Groups("class=\"shortstory-listab-title\"><a href=\"(https?://[^\"]+\\.html)\">([^<]+)</a>");
if (!string.IsNullOrWhiteSpace(g[1].Value) && !string.IsNullOrWhiteSpace(g[2].Value))
{
string season = "0";
if (g[2].Value.Contains("сезон"))
{
season = Regex.Match(g[2].Value, "([0-9]+) сезон").Groups[1].Value;
if (string.IsNullOrEmpty(season))
season = "1";
}
string img = row.Match("<img class=\"img-fit lozad\" data-src=\"([^\"]+)\"");
catalog.Add((g[2].Value, row.Match("\">([0-9]{4})</a>"), g[1].Value, season, img));
}
}
});
if ((catalog == null || catalog.Count == 0) && !reqOk)
return e.Fail("catalog", refresh_proxy: true);
return e.Success(catalog);
});
if (IsRhubFallback(cache))
goto rhubFallback;
if (cache.Value != null && cache.Value.Count == 0)
return OnError();
if (!similar && cache.Value != null && cache.Value.Count == 1)
return LocalRedirect(accsArgs($"/lite/animebesst?rjson={rjson}&title={HttpUtility.UrlEncode(title)}&uri={HttpUtility.UrlEncode(cache.Value[0].uri)}&s={cache.Value[0].s}"));
return await ContentTpl(cache, () =>
{
var stpl = new SimilarTpl(cache.Value.Count);
foreach (var res in cache.Value)
{
string _u = $"{host}/lite/animebesst?title={HttpUtility.UrlEncode(title)}&uri={HttpUtility.UrlEncode(res.uri)}&s={res.s}";
stpl.Append(res.title, res.year, string.Empty, _u, PosterApi.Size(res.img));
}
return stpl;
});
#endregion
}
else
{
#region Серии
var cache = await InvokeCacheResult<List<(string episode, string name, string uri)>>($"animebesst:playlist:{uri}", 30, async e =>
{
var links = new List<(string episode, string name, string uri)>(5);
await httpHydra.GetSpan(uri, news =>
{
string videoList = Rx.Match(news, "var videoList ?=([^\n\r]+)");
if (videoList == null)
return;
var match = Regex.Match(videoList, "\"id\":\"([0-9]+)( [^\"]+)?\",\"link\":\"(https?:)?\\\\/\\\\/([^\"]+)\"");
while (match.Success)
{
if (!string.IsNullOrWhiteSpace(match.Groups[1].Value) && !string.IsNullOrWhiteSpace(match.Groups[4].Value))
links.Add((match.Groups[1].Value, match.Groups[2].Value.Trim(), match.Groups[4].Value.Replace("\\", "")));
match = match.NextMatch();
}
});
if (links.Count == 0)
return e.Fail("links", refresh_proxy: true);
return e.Success(links);
});
if (IsRhubFallback(cache))
goto rhubFallback;
return await ContentTpl(cache, () =>
{
var etpl = new EpisodeTpl(cache.Value.Count);
foreach (var l in cache.Value)
{
string name = string.IsNullOrEmpty(l.name) ? $"{l.episode} серия" : $"{l.episode} {l.name}";
string voice_name = !string.IsNullOrEmpty(l.name) ? Regex.Replace(l.name, "(^\\(|\\)$)", "") : "";
string link = accsArgs($"{host}/lite/animebesst/video.m3u8?uri={HttpUtility.UrlEncode(l.uri)}&title={HttpUtility.UrlEncode(title)}");
etpl.Append(name, $"{title} / {name}", s.ToString(), l.episode, link, "call", streamlink: $"{link}&play=true", voice_name: Regex.Unescape(voice_name));
}
return etpl;
});
#endregion
}
}
#region Video
[HttpGet]
[Route("lite/animebesst/video.m3u8")]
async public ValueTask<ActionResult> Video(string uri, string title, bool play)
{
if (await IsRequestBlocked(rch: true, rch_check: false))
return badInitMsg;
if (rch != null)
{
if (rch.IsNotConnected())
{
if (init.rhub_fallback && play)
rch.Disabled();
else
return ContentTo(rch.connectionMsg);
}
if (!play && rch.IsRequiredConnected())
return ContentTo(rch.connectionMsg);
if (rch.IsNotSupport(out string rch_error))
return ShowError(rch_error);
}
rhubFallback:
var cache = await InvokeCacheResult<string>($"animebesst:video:{uri}", 30, async e =>
{
string hls = null;
await httpHydra.GetSpan($"https://{uri}", addheaders: HeadersModel.Init("referer", init.host), spanAction: iframe =>
{
hls = Rx.Match(iframe, "file:\"(https?://[^\"]+\\.m3u8)\"");
});
if (string.IsNullOrEmpty(hls))
return e.Fail("hls", refresh_proxy: true);
return e.Success(hls);
});
if (IsRhubFallback(cache))
goto rhubFallback;
if (!cache.IsSuccess)
return OnError(cache.ErrorMsg);
string link = HostStreamProxy(cache.Value);
if (play)
return RedirectToPlay(link);
return ContentTo(VideoTpl.ToJson("play", link, title, vast: init.vast));
}
#endregion
}
}