mirror of
https://github.com/lampame/lampac-ukraine.git
synced 2026-04-16 09:22:21 +00:00
343 lines
13 KiB
C#
343 lines
13 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using MoonAnime.Models;
|
|
using Shared;
|
|
using Shared.Engine;
|
|
using Shared.Models;
|
|
using Shared.Models.Online.Settings;
|
|
using Shared.Models.Templates;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using System.Web;
|
|
|
|
namespace MoonAnime.Controllers
|
|
{
|
|
public class Controller : BaseOnlineController
|
|
{
|
|
private readonly ProxyManager proxyManager;
|
|
|
|
public Controller() : base(ModInit.Settings)
|
|
{
|
|
proxyManager = new ProxyManager(ModInit.MoonAnime);
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("moonanime")]
|
|
public async 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 mal_id, string t, int s = -1, bool rjson = false, bool checksearch = false)
|
|
{
|
|
await UpdateService.ConnectAsync(host);
|
|
|
|
var init = await loadKit(ModInit.MoonAnime);
|
|
if (!init.enable)
|
|
return Forbid();
|
|
|
|
var invoke = new MoonAnimeInvoke(init, hybridCache, OnLog, proxyManager);
|
|
|
|
if (checksearch)
|
|
{
|
|
if (AppInit.conf?.online?.checkOnlineSearch != true)
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
var checkResults = await invoke.Search(imdb_id, mal_id, title, original_title, year);
|
|
if (checkResults != null && checkResults.Count > 0)
|
|
return Content("data-json=", "text/plain; charset=utf-8");
|
|
|
|
return OnError("moonanime", proxyManager);
|
|
}
|
|
|
|
OnLog($"MoonAnime: title={title}, original_title={original_title}, imdb={imdb_id}, mal_id={mal_id}, serial={serial}, s={s}, t={t}");
|
|
|
|
var seasons = await invoke.Search(imdb_id, mal_id, title, original_title, year);
|
|
if (seasons == null || seasons.Count == 0)
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
bool isSeries = serial == 1;
|
|
MoonAnimeSeasonContent firstSeasonData = null;
|
|
|
|
if (serial == -1)
|
|
{
|
|
firstSeasonData = await invoke.GetSeasonContent(seasons[0]);
|
|
if (firstSeasonData == null || firstSeasonData.Voices.Count == 0)
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
isSeries = firstSeasonData.IsSeries;
|
|
}
|
|
|
|
if (isSeries)
|
|
{
|
|
return await RenderSerial(invoke, seasons, imdb_id, kinopoisk_id, title, original_title, year, mal_id, s, t, rjson);
|
|
}
|
|
|
|
return await RenderMovie(invoke, seasons, title, original_title, firstSeasonData, rjson);
|
|
}
|
|
|
|
[HttpGet("moonanime/play")]
|
|
public async Task<ActionResult> Play(string file, string title = null)
|
|
{
|
|
await UpdateService.ConnectAsync(host);
|
|
|
|
var init = await loadKit(ModInit.MoonAnime);
|
|
if (!init.enable)
|
|
return Forbid();
|
|
|
|
if (string.IsNullOrWhiteSpace(file))
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
var invoke = new MoonAnimeInvoke(init, hybridCache, OnLog, proxyManager);
|
|
var streams = invoke.ParseStreams(file);
|
|
if (streams == null || streams.Count == 0)
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
if (streams.Count == 1)
|
|
{
|
|
string singleUrl = BuildStreamUrl(init, streams[0].Url);
|
|
string singleJson = VideoTpl.ToJson("play", singleUrl, title ?? string.Empty, quality: streams[0].Quality ?? "auto");
|
|
return UpdateService.Validate(Content(singleJson, "application/json; charset=utf-8"));
|
|
}
|
|
|
|
var streamQuality = new StreamQualityTpl();
|
|
foreach (var stream in streams)
|
|
{
|
|
string streamUrl = BuildStreamUrl(init, stream.Url);
|
|
streamQuality.Append(streamUrl, stream.Quality);
|
|
}
|
|
|
|
if (!streamQuality.Any())
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
var first = streamQuality.Firts();
|
|
string json = VideoTpl.ToJson("play", first.link, title ?? string.Empty, streamquality: streamQuality);
|
|
return UpdateService.Validate(Content(json, "application/json; charset=utf-8"));
|
|
}
|
|
|
|
private async Task<ActionResult> RenderSerial(
|
|
MoonAnimeInvoke invoke,
|
|
List<MoonAnimeSeasonRef> seasons,
|
|
string imdbId,
|
|
long kinopoiskId,
|
|
string title,
|
|
string originalTitle,
|
|
int year,
|
|
string malId,
|
|
int selectedSeason,
|
|
string selectedVoice,
|
|
bool rjson)
|
|
{
|
|
var orderedSeasons = seasons
|
|
.Where(s => s != null && !string.IsNullOrWhiteSpace(s.Url))
|
|
.OrderBy(s => s.SeasonNumber)
|
|
.ToList();
|
|
|
|
if (orderedSeasons.Count == 0)
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
if (selectedSeason == -1)
|
|
{
|
|
var seasonTpl = new SeasonTpl(orderedSeasons.Count);
|
|
foreach (var season in orderedSeasons)
|
|
{
|
|
int seasonNumber = season.SeasonNumber <= 0 ? 1 : season.SeasonNumber;
|
|
string seasonName = $"Сезон {seasonNumber}";
|
|
string seasonLink = BuildIndexUrl(imdbId, kinopoiskId, title, originalTitle, year, 1, malId, seasonNumber, selectedVoice);
|
|
seasonTpl.Append(seasonName, seasonLink, seasonNumber);
|
|
}
|
|
|
|
return rjson
|
|
? Content(seasonTpl.ToJson(), "application/json; charset=utf-8")
|
|
: Content(seasonTpl.ToHtml(), "text/html; charset=utf-8");
|
|
}
|
|
|
|
var currentSeason = orderedSeasons.FirstOrDefault(s => s.SeasonNumber == selectedSeason) ?? orderedSeasons[0];
|
|
var seasonData = await invoke.GetSeasonContent(currentSeason);
|
|
if (seasonData == null)
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
var voices = seasonData.Voices
|
|
.Where(v => v != null && v.Episodes != null && v.Episodes.Count > 0)
|
|
.ToList();
|
|
|
|
if (voices.Count == 0)
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
int activeVoiceIndex = ParseVoiceIndex(selectedVoice, voices.Count);
|
|
var voiceTpl = new VoiceTpl(voices.Count);
|
|
for (int i = 0; i < voices.Count; i++)
|
|
{
|
|
string voiceName = string.IsNullOrWhiteSpace(voices[i].Name) ? $"Озвучка {i + 1}" : voices[i].Name;
|
|
string voiceLink = BuildIndexUrl(imdbId, kinopoiskId, title, originalTitle, year, 1, malId, currentSeason.SeasonNumber, i.ToString());
|
|
voiceTpl.Append(voiceName, i == activeVoiceIndex, voiceLink);
|
|
}
|
|
|
|
var selectedVoiceData = voices[activeVoiceIndex];
|
|
var episodes = selectedVoiceData.Episodes
|
|
.Where(e => e != null && !string.IsNullOrWhiteSpace(e.File))
|
|
.OrderBy(e => e.Number <= 0 ? int.MaxValue : e.Number)
|
|
.ThenBy(e => e.Name)
|
|
.ToList();
|
|
|
|
if (episodes.Count == 0)
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
string displayTitle = !string.IsNullOrWhiteSpace(title)
|
|
? title
|
|
: !string.IsNullOrWhiteSpace(originalTitle)
|
|
? originalTitle
|
|
: "MoonAnime";
|
|
|
|
var episodeTpl = new EpisodeTpl(episodes.Count);
|
|
foreach (var episode in episodes)
|
|
{
|
|
int episodeNumber = episode.Number <= 0 ? 1 : episode.Number;
|
|
string episodeName = string.IsNullOrWhiteSpace(episode.Name) ? $"Епізод {episodeNumber}" : episode.Name;
|
|
string callUrl = $"{host}/moonanime/play?file={HttpUtility.UrlEncode(episode.File)}&title={HttpUtility.UrlEncode(displayTitle)}";
|
|
episodeTpl.Append(episodeName, displayTitle, currentSeason.SeasonNumber.ToString(), episodeNumber.ToString(), accsArgs(callUrl), "call");
|
|
}
|
|
|
|
episodeTpl.Append(voiceTpl);
|
|
|
|
return rjson
|
|
? Content(episodeTpl.ToJson(), "application/json; charset=utf-8")
|
|
: Content(episodeTpl.ToHtml(), "text/html; charset=utf-8");
|
|
}
|
|
|
|
private async Task<ActionResult> RenderMovie(
|
|
MoonAnimeInvoke invoke,
|
|
List<MoonAnimeSeasonRef> seasons,
|
|
string title,
|
|
string originalTitle,
|
|
MoonAnimeSeasonContent firstSeasonData,
|
|
bool rjson)
|
|
{
|
|
var currentSeason = seasons
|
|
.Where(s => s != null && !string.IsNullOrWhiteSpace(s.Url))
|
|
.OrderBy(s => s.SeasonNumber)
|
|
.FirstOrDefault();
|
|
|
|
if (currentSeason == null)
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
MoonAnimeSeasonContent 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("moonanime", proxyManager);
|
|
|
|
string displayTitle = !string.IsNullOrWhiteSpace(title)
|
|
? title
|
|
: !string.IsNullOrWhiteSpace(originalTitle)
|
|
? originalTitle
|
|
: "MoonAnime";
|
|
|
|
var movieTpl = new MovieTpl(displayTitle, originalTitle);
|
|
int fallbackIndex = 1;
|
|
|
|
foreach (var voice in seasonData.Voices)
|
|
{
|
|
if (voice == null)
|
|
continue;
|
|
|
|
string file = !string.IsNullOrWhiteSpace(voice.MovieFile)
|
|
? voice.MovieFile
|
|
: voice.Episodes?.FirstOrDefault(e => !string.IsNullOrWhiteSpace(e.File))?.File;
|
|
|
|
if (string.IsNullOrWhiteSpace(file))
|
|
continue;
|
|
|
|
string voiceName = string.IsNullOrWhiteSpace(voice.Name) ? $"Озвучка {fallbackIndex}" : voice.Name;
|
|
string callUrl = $"{host}/moonanime/play?file={HttpUtility.UrlEncode(file)}&title={HttpUtility.UrlEncode(displayTitle)}";
|
|
movieTpl.Append(voiceName, accsArgs(callUrl), "call");
|
|
fallbackIndex++;
|
|
}
|
|
|
|
if (movieTpl.IsEmpty)
|
|
return OnError("moonanime", proxyManager);
|
|
|
|
return rjson
|
|
? Content(movieTpl.ToJson(), "application/json; charset=utf-8")
|
|
: Content(movieTpl.ToHtml(), "text/html; charset=utf-8");
|
|
}
|
|
|
|
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}/moonanime?imdb_id={HttpUtility.UrlEncode(imdbId)}");
|
|
url.Append($"&kinopoisk_id={kinopoiskId}");
|
|
url.Append($"&title={HttpUtility.UrlEncode(title)}");
|
|
url.Append($"&original_title={HttpUtility.UrlEncode(originalTitle)}");
|
|
url.Append($"&year={year}");
|
|
url.Append($"&serial={serial}");
|
|
|
|
if (!string.IsNullOrWhiteSpace(malId))
|
|
url.Append($"&mal_id={HttpUtility.UrlEncode(malId)}");
|
|
|
|
if (season > 0)
|
|
url.Append($"&s={season}");
|
|
|
|
if (!string.IsNullOrWhiteSpace(voice))
|
|
url.Append($"&t={HttpUtility.UrlEncode(voice)}");
|
|
|
|
return url.ToString();
|
|
}
|
|
|
|
private int ParseVoiceIndex(string voiceValue, int totalVoices)
|
|
{
|
|
if (totalVoices <= 0)
|
|
return 0;
|
|
|
|
if (!int.TryParse(voiceValue, out int index))
|
|
return 0;
|
|
|
|
if (index < 0 || index >= totalVoices)
|
|
return 0;
|
|
|
|
return index;
|
|
}
|
|
|
|
private string BuildStreamUrl(OnlinesSettings init, string streamLink)
|
|
{
|
|
string link = StripLampacArgs(streamLink?.Trim());
|
|
if (string.IsNullOrEmpty(link))
|
|
return link;
|
|
|
|
var headers = new List<HeadersModel>
|
|
{
|
|
new HeadersModel("User-Agent", "Mozilla/5.0"),
|
|
new HeadersModel("Referer", "https://moonanime.art/")
|
|
};
|
|
|
|
if (ApnHelper.IsEnabled(init))
|
|
{
|
|
if (ModInit.ApnHostProvided)
|
|
return ApnHelper.WrapUrl(init, link);
|
|
|
|
var noApn = (OnlinesSettings)init.Clone();
|
|
noApn.apnstream = false;
|
|
noApn.apn = null;
|
|
return HostStreamProxy(noApn, link, headers: headers, proxy: proxyManager.Get());
|
|
}
|
|
|
|
return HostStreamProxy(init, link, headers: headers, proxy: proxyManager.Get());
|
|
}
|
|
|
|
private static string StripLampacArgs(string url)
|
|
{
|
|
if (string.IsNullOrEmpty(url))
|
|
return url;
|
|
|
|
string cleaned = Regex.Replace(
|
|
url,
|
|
@"([?&])(account_email|uid|nws_id)=[^&]*",
|
|
"$1",
|
|
RegexOptions.IgnoreCase
|
|
);
|
|
|
|
cleaned = cleaned.Replace("?&", "?").Replace("&&", "&").TrimEnd('?', '&');
|
|
return cleaned;
|
|
}
|
|
}
|
|
}
|