mirror of
https://github.com/lampame/lampac-ukraine.git
synced 2026-04-16 17:32:20 +00:00
The changes fix missing commas between base64-encoded strings in configuration arrays across multiple service modules. This ensures proper parsing of the configuration values during runtime. Affected modules: - Anihub - AnimeON - Bamboo - CikavaIdeya - StarLight - UAKino - UaTUT - Uaflix - Unimay
380 lines
19 KiB
C#
380 lines
19 KiB
C#
using Shared.Engine;
|
||
using System;
|
||
using System.Threading.Tasks;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using System.Collections.Generic;
|
||
using System.Web;
|
||
using System.Linq;
|
||
using Shared;
|
||
using Shared.Models.Templates;
|
||
using Anihub.Models;
|
||
using System.Text.RegularExpressions;
|
||
using Shared.Models.Online.Settings;
|
||
using Shared.Models;
|
||
using System.Net;
|
||
using System.Net.Http;
|
||
using System.Text;
|
||
|
||
namespace Anihub
|
||
{
|
||
[Route("anihub")]
|
||
public class AnihubController : BaseOnlineController
|
||
{
|
||
private static readonly HashSet<string> NotAllowedHosts =
|
||
new HashSet<string>(
|
||
new[]
|
||
{
|
||
"c3ZpdGFubW92aWU=",
|
||
"cG9ydGFsLXR2",
|
||
"bGFtcGEuc3RyZWFt",
|
||
}
|
||
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
|
||
StringComparer.OrdinalIgnoreCase
|
||
);
|
||
ProxyManager proxyManager;
|
||
|
||
public AnihubController()
|
||
{
|
||
proxyManager = new ProxyManager(ModInit.Anihub);
|
||
}
|
||
|
||
[HttpGet]
|
||
async public 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 t, int s = -1, bool rjson = false)
|
||
{
|
||
var init = await loadKit(ModInit.Anihub);
|
||
if (!init.enable)
|
||
return OnError();
|
||
|
||
OnLog($"Anihub: {title} (serial={serial}, s={s}, t={t})");
|
||
|
||
var invoke = new AnihubInvoke(init, hybridCache, OnLog, proxyManager);
|
||
|
||
var searchResponse = await invoke.Search(title, original_title, "0", year.ToString());
|
||
if (searchResponse == null || searchResponse.IsEmpty)
|
||
return OnError();
|
||
|
||
if (serial == 1)
|
||
{
|
||
if (s == -1) // Відображення списку аніме як "сезонів"
|
||
{
|
||
var season_tpl = new SeasonTpl();
|
||
for (int i = 0; i < searchResponse.content.Count; i++)
|
||
{
|
||
var anime = searchResponse.content[i];
|
||
string seasonName = anime.TitleUkrainian ?? anime.TitleEnglish ?? anime.TitleOriginal;
|
||
string link = $"{host}/anihub?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={i}";
|
||
season_tpl.Append(seasonName, link, i.ToString());
|
||
}
|
||
|
||
OnLog($"Anihub: generated {searchResponse.content.Count} seasons");
|
||
return rjson ? Content(season_tpl.ToJson(), "application/json; charset=utf-8") : Content(season_tpl.ToHtml(), "text/html; charset=utf-8");
|
||
}
|
||
else // Відображення озвучок та епізодів для вибраного аніме
|
||
{
|
||
if (s >= searchResponse.content.Count)
|
||
return OnError();
|
||
|
||
var selectedAnime = searchResponse.content[s];
|
||
var episodesResponse = await invoke.Embed(selectedAnime.Id.ToString());
|
||
if (episodesResponse == null)
|
||
return OnError();
|
||
|
||
var voice_tpl = new VoiceTpl();
|
||
var episode_tpl = new EpisodeTpl();
|
||
|
||
// Автоматично вибираємо першу озвучку якщо не вибрана
|
||
string selectedVoice = t;
|
||
if (string.IsNullOrEmpty(selectedVoice))
|
||
{
|
||
if (episodesResponse.Moonanime.Count > 0)
|
||
selectedVoice = $"moon_{episodesResponse.Moonanime.First().Id}";
|
||
else if (episodesResponse.Ashdi.Count > 0)
|
||
selectedVoice = $"ashdi_{episodesResponse.Ashdi.First().Id}";
|
||
}
|
||
|
||
// Додаємо озвучки з Moonanime
|
||
foreach (var moonSource in episodesResponse.Moonanime)
|
||
{
|
||
string voiceName = $"[Moon] {moonSource.StudioName}";
|
||
string voiceLink = $"{host}/anihub?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={s}&t=moon_{moonSource.Id}";
|
||
bool isActive = selectedVoice != null && selectedVoice.StartsWith("moon_") && selectedVoice.Split('_')[1] == moonSource.Id.ToString();
|
||
voice_tpl.Append(voiceName, isActive, voiceLink);
|
||
}
|
||
|
||
// Додаємо озвучки з Ashdi
|
||
foreach (var ashdiSource in episodesResponse.Ashdi)
|
||
{
|
||
string voiceName = $"[Ashdi] {ashdiSource.StudioName}";
|
||
string voiceLink = $"{host}/anihub?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={s}&t=ashdi_{ashdiSource.Id}";
|
||
bool isActive = selectedVoice != null && selectedVoice.StartsWith("ashdi_") && selectedVoice.Split('_')[1] == ashdiSource.Id.ToString();
|
||
voice_tpl.Append(voiceName, isActive, voiceLink);
|
||
}
|
||
|
||
// Завжди додаємо епізоди для вибраної озвучки (або автоматично вибраної)
|
||
if (!string.IsNullOrEmpty(selectedVoice))
|
||
{
|
||
if (selectedVoice.StartsWith("moon_"))
|
||
{
|
||
var parts = selectedVoice.Split('_');
|
||
if (parts.Length >= 2 && int.TryParse(parts[1], out int sourceId))
|
||
{
|
||
var selectedSource = episodesResponse.Moonanime.FirstOrDefault(m => m.Id == sourceId);
|
||
if (selectedSource != null)
|
||
{
|
||
foreach (var episode in selectedSource.Episodes.OrderBy(e => e.EpisodeNumber))
|
||
{
|
||
string episodeName = !string.IsNullOrEmpty(episode.Title) ? episode.Title : $"Епізод {episode.EpisodeNumber}";
|
||
string episodeLink = $"{host}/anihub/play?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&s={s}&e={episode.EpisodeNumber}&t={selectedVoice}_{episode.Id}";
|
||
episode_tpl.Append(episodeName, title ?? original_title, s.ToString(), episode.EpisodeNumber.ToString("D2"), episodeLink, "call");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if (selectedVoice.StartsWith("ashdi_"))
|
||
{
|
||
var parts = selectedVoice.Split('_');
|
||
if (parts.Length >= 2 && int.TryParse(parts[1], out int sourceId))
|
||
{
|
||
var selectedSource = episodesResponse.Ashdi.FirstOrDefault(a => a.Id == sourceId);
|
||
if (selectedSource != null)
|
||
{
|
||
foreach (var episodeData in selectedSource.EpisodesData.OrderBy(e => e.EpisodeNumber))
|
||
{
|
||
string episodeName = !string.IsNullOrEmpty(episodeData.Title) ? episodeData.Title : $"Епізод {episodeData.EpisodeNumber}";
|
||
string episodeLink = $"{host}/anihub/play?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&s={s}&e={episodeData.EpisodeNumber}&t={selectedVoice}_{episodeData.Id}";
|
||
episode_tpl.Append(episodeName, title ?? original_title, s.ToString(), episodeData.EpisodeNumber.ToString("D2"), episodeLink, "call");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
int voiceCount = episodesResponse.Moonanime.Count + episodesResponse.Ashdi.Count;
|
||
int episodeCount = 0;
|
||
if (!string.IsNullOrEmpty(selectedVoice))
|
||
{
|
||
if (selectedVoice.StartsWith("moon_"))
|
||
{
|
||
var parts = selectedVoice.Split('_');
|
||
if (parts.Length >= 2 && int.TryParse(parts[1], out int sourceId))
|
||
{
|
||
var selectedSource = episodesResponse.Moonanime.FirstOrDefault(m => m.Id == sourceId);
|
||
episodeCount = selectedSource?.Episodes?.Count ?? 0;
|
||
}
|
||
}
|
||
else if (selectedVoice.StartsWith("ashdi_"))
|
||
{
|
||
var parts = selectedVoice.Split('_');
|
||
if (parts.Length >= 2 && int.TryParse(parts[1], out int sourceId))
|
||
{
|
||
var selectedSource = episodesResponse.Ashdi.FirstOrDefault(a => a.Id == sourceId);
|
||
episodeCount = selectedSource?.EpisodesData?.Count ?? 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
OnLog($"Anihub: generated {voiceCount} voices, {episodeCount} episodes");
|
||
|
||
if (rjson)
|
||
return Content(episode_tpl.ToJson(voice_tpl), "application/json; charset=utf-8");
|
||
|
||
return Content(voice_tpl.ToHtml() + episode_tpl.ToHtml(), "text/html; charset=utf-8");
|
||
}
|
||
}
|
||
else // Фільм
|
||
{
|
||
var firstAnime = searchResponse.content.FirstOrDefault();
|
||
if (firstAnime == null)
|
||
return OnError();
|
||
|
||
var episodesResponse = await invoke.Embed(firstAnime.Id.ToString());
|
||
if (episodesResponse == null)
|
||
return OnError();
|
||
|
||
var movie_tpl = new MovieTpl(title, original_title);
|
||
|
||
// Обробляємо джерела Moonanime
|
||
foreach (var moonSource in episodesResponse.Moonanime)
|
||
{
|
||
foreach (var episode in moonSource.Episodes)
|
||
{
|
||
string voiceName = $"[Moon] {moonSource.StudioName}";
|
||
string link = $"{host}/anihub/play?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&s=0&e={episode.EpisodeNumber}&t=moon_{moonSource.Id}_{episode.Id}";
|
||
movie_tpl.Append(voiceName, link, "call");
|
||
}
|
||
}
|
||
|
||
// Обробляємо джерела Ashdi
|
||
foreach (var ashdiSource in episodesResponse.Ashdi)
|
||
{
|
||
foreach (var episodeData in ashdiSource.EpisodesData)
|
||
{
|
||
string voiceName = $"[Ashdi] {ashdiSource.StudioName}";
|
||
string link = $"{host}/anihub/play?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&s=0&e={episodeData.EpisodeNumber}&t=ashdi_{ashdiSource.Id}_{episodeData.Id}";
|
||
movie_tpl.Append(voiceName, link, "call");
|
||
}
|
||
}
|
||
|
||
int totalOptions = 0;
|
||
foreach (var moonSource in episodesResponse.Moonanime)
|
||
totalOptions += moonSource.Episodes.Count;
|
||
foreach (var ashdiSource in episodesResponse.Ashdi)
|
||
totalOptions += ashdiSource.EpisodesData.Count;
|
||
|
||
OnLog($"Anihub: generated {totalOptions} movie options");
|
||
return rjson ? Content(movie_tpl.ToJson(), "application/json; charset=utf-8") : Content(movie_tpl.ToHtml(), "text/html; charset=utf-8");
|
||
}
|
||
}
|
||
|
||
[HttpGet]
|
||
[Route("play")]
|
||
async public Task<ActionResult> Play(string imdb_id, long kinopoisk_id, string title, string original_title, int year, int s, int e, string t, bool play = false)
|
||
{
|
||
var init = await loadKit(ModInit.Anihub);
|
||
if (!init.enable)
|
||
return OnError();
|
||
|
||
OnLog($"Anihub play: {title} s={s} e={e} ({t})");
|
||
|
||
var invoke = new AnihubInvoke(init, hybridCache, OnLog, proxyManager);
|
||
|
||
// Парсимо токен озвучки/джерела
|
||
if (string.IsNullOrEmpty(t))
|
||
return OnError();
|
||
|
||
var parts = t.Split('_');
|
||
if (parts.Length < 3)
|
||
return OnError();
|
||
|
||
string sourceType = parts[0];
|
||
if (!int.TryParse(parts[1], out int sourceId) || !int.TryParse(parts[2], out int episodeId))
|
||
return OnError();
|
||
|
||
// Знаходимо аніме та отримуємо джерела епізодів
|
||
var searchResponse = await invoke.Search(title, original_title, "0", year.ToString());
|
||
if (searchResponse == null || searchResponse.IsEmpty || s >= searchResponse.content.Count)
|
||
return OnError();
|
||
|
||
var selectedAnime = searchResponse.content[s];
|
||
var episodesResponse = await invoke.Embed(selectedAnime.Id.ToString());
|
||
if (episodesResponse == null)
|
||
return OnError();
|
||
|
||
string iframeUrl = null;
|
||
|
||
if (sourceType == "moon")
|
||
{
|
||
var moonSource = episodesResponse.Moonanime.FirstOrDefault(m => m.Id == sourceId);
|
||
var episode = moonSource?.Episodes.FirstOrDefault(ep => ep.Id == episodeId);
|
||
iframeUrl = episode?.IframeLink;
|
||
}
|
||
else if (sourceType == "ashdi")
|
||
{
|
||
var ashdiSource = episodesResponse.Ashdi.FirstOrDefault(a => a.Id == sourceId);
|
||
var episodeData = ashdiSource?.EpisodesData.FirstOrDefault(ep => ep.Id == episodeId.ToString());
|
||
iframeUrl = episodeData?.VodUrl;
|
||
}
|
||
|
||
if (string.IsNullOrEmpty(iframeUrl))
|
||
{
|
||
OnLog($"Anihub play: iframe URL not found for {sourceType}");
|
||
return OnError();
|
||
}
|
||
|
||
// Отримуємо пряме посилання на потік
|
||
string streamUrl = await ExtractStreamUrl(iframeUrl, sourceType);
|
||
|
||
if (string.IsNullOrEmpty(streamUrl))
|
||
{
|
||
OnLog($"Anihub play: stream extraction failed for {sourceType}");
|
||
return OnError();
|
||
}
|
||
|
||
OnLog($"Anihub play: extracted {sourceType} stream");
|
||
|
||
// Якщо play=true, робимо Redirect, інакше повертаємо JSON
|
||
if (play)
|
||
return Redirect(streamUrl);
|
||
else
|
||
return Content(VideoTpl.ToJson("play", streamUrl, title ?? original_title), "application/json; charset=utf-8");
|
||
}
|
||
|
||
private async Task<string> ExtractStreamUrl(string iframeUrl, string sourceType)
|
||
{
|
||
try
|
||
{
|
||
string requestUrl = iframeUrl;
|
||
|
||
// Додаємо параметр player тільки для Moon
|
||
if (sourceType == "moon")
|
||
{
|
||
requestUrl = iframeUrl + (iframeUrl.Contains("?") ? "&" : "?") + $"player={host}";
|
||
}
|
||
|
||
if (IsNotAllowedHost(requestUrl))
|
||
return null;
|
||
|
||
// Створюємо HTTP клієнт з правильними заголовками
|
||
using var httpClient = new HttpClient();
|
||
|
||
if (sourceType == "moon")
|
||
{
|
||
httpClient.DefaultRequestHeaders.Add("Referer", "https://moonanime.art/");
|
||
httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
|
||
httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8");
|
||
httpClient.DefaultRequestHeaders.Add("Accept-Language", "uk-UA,uk;q=0.9,en-US;q=0.8,en;q=0.7");
|
||
}
|
||
else
|
||
{
|
||
httpClient.DefaultRequestHeaders.Add("Referer", host);
|
||
httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0.1 Safari/605.1.15");
|
||
}
|
||
|
||
// Робимо запит до плеєра
|
||
OnLog($"Anihub player: requesting {sourceType} iframe");
|
||
var response = await httpClient.GetStringAsync(requestUrl);
|
||
|
||
if (string.IsNullOrEmpty(response))
|
||
return null;
|
||
|
||
// Парсимо відповідь для отримання file URL
|
||
string streamUrl = null;
|
||
|
||
if (sourceType == "ashdi")
|
||
{
|
||
var match = Regex.Match(response, @"file:'([^']+)'");
|
||
if (match.Success)
|
||
streamUrl = match.Groups[1].Value;
|
||
}
|
||
else if (sourceType == "moon")
|
||
{
|
||
var match = Regex.Match(response, @"file:\s*""([^""]+)""");
|
||
if (match.Success)
|
||
streamUrl = match.Groups[1].Value;
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(streamUrl))
|
||
OnLog($"Anihub player: extracted {sourceType} stream");
|
||
|
||
return streamUrl;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
OnLog($"Anihub player: {sourceType} error - {ex.Message}");
|
||
return null;
|
||
}
|
||
}
|
||
|
||
private static bool IsNotAllowedHost(string url)
|
||
{
|
||
if (string.IsNullOrEmpty(url))
|
||
return false;
|
||
|
||
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
|
||
return false;
|
||
|
||
return NotAllowedHosts.Contains(uri.Host);
|
||
}
|
||
}
|
||
}
|