lampac-ukraine/NMoonAnime/Controller.cs

343 lines
14 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 NMoonAnime.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 NMoonAnime.Controllers
{
public class Controller : BaseOnlineController
{
private readonly ProxyManager proxyManager;
public Controller() : base(ModInit.Settings)
{
proxyManager = new ProxyManager(ModInit.NMoonAnime);
}
[HttpGet]
[Route("nmoonanime")]
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.NMoonAnime);
if (!init.enable)
return Forbid();
var invoke = new NMoonAnimeInvoke(init, hybridCache, OnLog, proxyManager);
if (checksearch)
{
if (AppInit.conf?.online?.checkOnlineSearch != true)
return OnError("nmoonanime", 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("nmoonanime", proxyManager);
}
OnLog($"NMoonAnime: назва={title}, оригінальнаазва={original_title}, imdb={imdb_id}, mal_id={mal_id}, серіал={serial}, сезон={s}, озвучка={t}");
var seasons = await invoke.Search(imdb_id, mal_id, title, original_title, year);
if (seasons == null || seasons.Count == 0)
return OnError("nmoonanime", proxyManager);
bool isSeries = serial == 1;
NMoonAnimeSeasonContent firstSeasonData = null;
if (serial == -1)
{
firstSeasonData = await invoke.GetSeasonContent(seasons[0]);
if (firstSeasonData == null || firstSeasonData.Voices.Count == 0)
return OnError("nmoonanime", 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("nmoonanime/play")]
public async Task<ActionResult> Play(string file, string title = null)
{
await UpdateService.ConnectAsync(host);
var init = await loadKit(ModInit.NMoonAnime);
if (!init.enable)
return Forbid();
if (string.IsNullOrWhiteSpace(file))
return OnError("nmoonanime", proxyManager);
var invoke = new NMoonAnimeInvoke(init, hybridCache, OnLog, proxyManager);
var streams = invoke.ParseStreams(file);
if (streams == null || streams.Count == 0)
return OnError("nmoonanime", 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("nmoonanime", 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(
NMoonAnimeInvoke invoke,
List<NMoonAnimeSeasonRef> 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("nmoonanime", 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("nmoonanime", proxyManager);
var voices = seasonData.Voices
.Where(v => v != null && v.Episodes != null && v.Episodes.Count > 0)
.ToList();
if (voices.Count == 0)
return OnError("nmoonanime", 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("nmoonanime", proxyManager);
string displayTitle = !string.IsNullOrWhiteSpace(title)
? title
: !string.IsNullOrWhiteSpace(originalTitle)
? originalTitle
: "NMoonAnime";
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}/nmoonanime/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(
NMoonAnimeInvoke invoke,
List<NMoonAnimeSeasonRef> seasons,
string title,
string originalTitle,
NMoonAnimeSeasonContent firstSeasonData,
bool rjson)
{
var currentSeason = seasons
.Where(s => s != null && !string.IsNullOrWhiteSpace(s.Url))
.OrderBy(s => s.SeasonNumber)
.FirstOrDefault();
if (currentSeason == null)
return OnError("nmoonanime", proxyManager);
NMoonAnimeSeasonContent 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("nmoonanime", proxyManager);
string displayTitle = !string.IsNullOrWhiteSpace(title)
? title
: !string.IsNullOrWhiteSpace(originalTitle)
? originalTitle
: "NMoonAnime";
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}/nmoonanime/play?file={HttpUtility.UrlEncode(file)}&title={HttpUtility.UrlEncode(displayTitle)}";
movieTpl.Append(voiceName, accsArgs(callUrl), "call");
fallbackIndex++;
}
if (movieTpl.IsEmpty)
return OnError("nmoonanime", 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}/nmoonanime?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;
}
}
}