Felix 543aa5f047 refactor: replace dots with underscores in module route paths and identifiers
- Updated all HTTP route paths from "lite/lme.module" to "lite/lme_module" across LME.AnimeON, LME.Bamboo, LME.JackTor, LME.KlonFUN, LME.Makhno, LME.Mikai, LME.NMoonAnime, LME.StarLight, LME.UafilmME, LME.Uaflix, and LME.Unimay controllers
- Standardized error messages, log prefixes, cache keys, and other string identifiers to use underscores instead of dots for consistency with naming conventions
- Applied changes to ModInit.cs, OnlineApi.cs, and invoke classes to maintain uniformity in module references
2026-04-12 11:14:26 +03:00

357 lines
15 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;
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.Threading.Tasks;
using System.Web;
using LME.UafilmME.Models;
namespace LME.UafilmME.Controllers
{
public class Controller : BaseOnlineController
{
ProxyManager proxyManager;
public Controller() : base(ModInit.Settings)
{
proxyManager = new ProxyManager(ModInit.UafilmME);
}
[HttpGet]
[Route("lite/lme_uafilmme")]
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, string href = null, bool checksearch = false)
{
await UpdateService.ConnectAsync(host);
var init = loadKit(ModInit.UafilmME);
if (!init.enable)
return Forbid();
var invoke = new UafilmMEInvoke(init, hybridCache, OnLog, proxyManager, httpHydra);
if (checksearch)
{
if (!IsCheckOnlineSearchEnabled())
return OnError("lme_uafilmme", refresh_proxy: true);
var searchResults = await invoke.Search(title, original_title, year);
if (searchResults != null && searchResults.Count > 0)
return Content("data-json=", "text/plain; charset=utf-8");
return OnError("lme_uafilmme", refresh_proxy: true);
}
long titleId = 0;
long.TryParse(href, out titleId);
if (titleId <= 0)
{
var searchResults = await invoke.Search(title, original_title, year);
if (searchResults == null || searchResults.Count == 0)
{
OnLog("lme_uafilmme: пошук нічого не повернув.");
return OnError("lme_uafilmme", refresh_proxy: true);
}
var best = invoke.SelectBestSearchResult(searchResults, id, imdb_id, title, original_title, year, serial);
var ordered = searchResults
.OrderByDescending(r => r.MatchScore)
.ThenByDescending(r => r.Year)
.ToList();
var second = ordered.Skip(1).FirstOrDefault();
if (!IsConfidentMatch(best, second, id, imdb_id, serial))
{
var similarTpl = new SimilarTpl(ordered.Count);
foreach (var item in ordered.Take(60))
{
string details = item.IsSeries ? "Серіал" : "Фільм";
string itemYear = item.Year > 1900 ? item.Year.ToString() : string.Empty;
string link = $"{host}/lite/lme_uafilmme?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial={serial}&href={item.Id}";
similarTpl.Append(item.Name, itemYear, details, link, item.Poster);
}
OnLog($"lme_uafilmme: кілька схожих збігів, повертаю SimilarTpl ({ordered.Count}).");
return rjson
? Content(similarTpl.ToJson(), "application/json; charset=utf-8")
: Content(similarTpl.ToHtml(), "text/html; charset=utf-8");
}
titleId = best?.Id ?? 0;
}
if (titleId <= 0)
{
OnLog("lme_uafilmme: не вдалося визначити title_id.");
return OnError("lme_uafilmme", refresh_proxy: true);
}
if (serial == 1)
{
if (s == -1)
{
var seasons = await invoke.GetAllSeasons(titleId);
if (seasons == null || seasons.Count == 0)
{
OnLog($"lme_uafilmme: сезони не знайдено для title_id={titleId}.");
return OnError("lme_uafilmme", refresh_proxy: true);
}
var seasonTpl = new SeasonTpl(seasons.Count);
foreach (var season in seasons)
{
string seasonName = season.EpisodesCount > 0
? $"Сезон {season.Number} ({season.EpisodesCount} еп.)"
: $"Сезон {season.Number}";
string link = $"{host}/lite/lme_uafilmme?imdb_id={imdb_id}&kinopoisk_id={kinopoisk_id}&title={HttpUtility.UrlEncode(title)}&original_title={HttpUtility.UrlEncode(original_title)}&year={year}&serial=1&s={season.Number}&href={titleId}";
seasonTpl.Append(seasonName, link, season.Number.ToString());
}
return rjson
? Content(seasonTpl.ToJson(), "application/json; charset=utf-8")
: Content(seasonTpl.ToHtml(), "text/html; charset=utf-8");
}
if (s <= 0)
{
OnLog($"lme_uafilmme: некоректний номер сезону s={s}.");
return OnError("lme_uafilmme", refresh_proxy: true);
}
var episodes = await invoke.GetSeasonEpisodes(titleId, s);
if (episodes == null || episodes.Count == 0)
{
OnLog($"lme_uafilmme: епізоди не знайдено для title_id={titleId}, season={s}.");
return OnError("lme_uafilmme", refresh_proxy: true);
}
var episodeTpl = new EpisodeTpl();
int appended = 0;
int fallbackEpisodeNumber = 1;
foreach (var episode in episodes)
{
if (episode.PrimaryVideoId <= 0)
continue;
int episodeNumber = episode.EpisodeNumber > 0 ? episode.EpisodeNumber : fallbackEpisodeNumber;
string episodeName = !string.IsNullOrWhiteSpace(episode.Name)
? episode.Name
: $"Епізод {episodeNumber}";
string callUrl = $"{host}/lite/lme_uafilmme/play?video_id={episode.PrimaryVideoId}&title_id={titleId}&s={s}&e={episodeNumber}&title={HttpUtility.UrlEncode(title ?? original_title)}";
episodeTpl.Append(episodeName, title ?? original_title, s.ToString(), episodeNumber.ToString("D2"), accsArgs(callUrl), "call");
fallbackEpisodeNumber = Math.Max(fallbackEpisodeNumber, episodeNumber + 1);
appended++;
}
if (appended == 0)
{
OnLog($"lme_uafilmme: у сезоні {s} немає епізодів з playable video_id.");
return OnError("lme_uafilmme", refresh_proxy: true);
}
return rjson
? Content(episodeTpl.ToJson(), "application/json; charset=utf-8")
: Content(episodeTpl.ToHtml(), "text/html; charset=utf-8");
}
else
{
var videos = await invoke.GetMovieVideos(titleId);
if (videos == null || videos.Count == 0)
{
OnLog($"lme_uafilmme: не знайдено відео для фільму title_id={titleId}.");
return OnError("lme_uafilmme", refresh_proxy: true);
}
var movieTpl = new MovieTpl(title, original_title, videos.Count);
int index = 1;
foreach (var video in videos)
{
string label = BuildVideoLabel(video, index);
string callUrl = $"{host}/lite/lme_uafilmme/play?video_id={video.Id}&title_id={titleId}&title={HttpUtility.UrlEncode(title ?? original_title)}";
movieTpl.Append(label, accsArgs(callUrl), "call");
index++;
}
return rjson
? Content(movieTpl.ToJson(), "application/json; charset=utf-8")
: Content(movieTpl.ToHtml(), "text/html; charset=utf-8");
}
}
[HttpGet]
[Route("lite/lme_uafilmme/play")]
async public Task<ActionResult> Play(long video_id, long title_id = 0, int s = 0, int e = 0, string title = null)
{
await UpdateService.ConnectAsync(host);
if (video_id <= 0)
return OnError("lme_uafilmme", refresh_proxy: true);
var init = loadKit(ModInit.UafilmME);
if (!init.enable)
return Forbid();
var invoke = new UafilmMEInvoke(init, hybridCache, OnLog, proxyManager, httpHydra);
var watch = await invoke.GetWatch(video_id);
var videos = invoke.CollectPlayableVideos(watch);
if (videos == null || videos.Count == 0)
{
OnLog($"lme_uafilmme Play: watch/{video_id} не повернув playable stream.");
return OnError("lme_uafilmme", refresh_proxy: true);
}
var headers = new List<HeadersModel>()
{
new HeadersModel("User-Agent", "Mozilla/5.0"),
new HeadersModel("Referer", init.host)
};
var streamQuality = new StreamQualityTpl();
foreach (var video in videos)
{
string streamUrl = BuildStreamUrl(init, video.Src, headers, forceProxy: true);
if (string.IsNullOrWhiteSpace(streamUrl))
continue;
string label = BuildVideoLabel(video, 0);
streamQuality.Append(streamUrl, label);
}
var first = streamQuality.Firts();
if (string.IsNullOrWhiteSpace(first.link))
{
OnLog($"lme_uafilmme Play: не вдалося зібрати streamquality для video_id={video_id}.");
return OnError("lme_uafilmme", refresh_proxy: true);
}
string videoTitle = !string.IsNullOrWhiteSpace(title)
? title
: videos.FirstOrDefault(v => !string.IsNullOrWhiteSpace(v.Name))?.Name ?? string.Empty;
return UpdateService.Validate(
Content(
VideoTpl.ToJson("play", first.link, videoTitle, streamquality: streamQuality),
"application/json; charset=utf-8"
)
);
}
string BuildStreamUrl(OnlinesSettings init, string streamLink, List<HeadersModel> headers, bool forceProxy)
{
string link = StripLampacArgs(streamLink?.Trim());
if (string.IsNullOrEmpty(link))
return link;
if (ApnHelper.IsEnabled(init))
{
if (ModInit.ApnHostProvided || ApnHelper.IsAshdiUrl(link))
return ApnHelper.WrapUrl(init, link);
var noApn = (OnlinesSettings)init.Clone();
noApn.apnstream = false;
noApn.apn = null;
return HostStreamProxy(noApn, link, headers: headers, force_streamproxy: forceProxy, proxy: proxyManager.Get());
}
return HostStreamProxy(init, link, headers: headers, force_streamproxy: forceProxy, proxy: proxyManager.Get());
}
private static bool IsConfidentMatch(UafilmSearchItem best, UafilmSearchItem second, long tmdbId, string imdbId, int serial)
{
if (best == null)
return false;
bool sameTmdb = tmdbId > 0 && best.TmdbId == tmdbId;
bool sameImdb = !string.IsNullOrWhiteSpace(imdbId)
&& !string.IsNullOrWhiteSpace(best.ImdbId)
&& string.Equals(best.ImdbId.Trim(), imdbId.Trim(), StringComparison.OrdinalIgnoreCase);
if (sameTmdb || sameImdb)
return true;
if (serial == 1 && !best.IsSeries)
return false;
int secondScore = second?.MatchScore ?? int.MinValue;
return best.MatchScore >= 65 && best.MatchScore - secondScore >= 10;
}
private static string BuildVideoLabel(UafilmVideoItem video, int index)
{
var parts = new List<string>();
if (!string.IsNullOrWhiteSpace(video?.Name))
parts.Add(video.Name.Trim());
if (!string.IsNullOrWhiteSpace(video?.Quality))
parts.Add(video.Quality.Trim());
if (!string.IsNullOrWhiteSpace(video?.Language))
parts.Add(video.Language.Trim());
if (parts.Count == 0)
return index > 0 ? $"Варіант {index}" : "Потік";
return string.Join(" • ", parts.Distinct(StringComparer.OrdinalIgnoreCase));
}
private static string StripLampacArgs(string url)
{
if (string.IsNullOrEmpty(url))
return url;
string cleaned = System.Text.RegularExpressions.Regex.Replace(
url,
@"([?&])(account_email|uid|nws_id)=[^&]*",
"$1",
System.Text.RegularExpressions.RegexOptions.IgnoreCase
);
cleaned = cleaned.Replace("?&", "?").Replace("&&", "&").TrimEnd('?', '&');
return cleaned;
}
private static bool IsCheckOnlineSearchEnabled()
{
try
{
var onlineType = Type.GetType("Online.ModInit");
if (onlineType == null)
{
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
onlineType = asm.GetType("Online.ModInit");
if (onlineType != null)
break;
}
}
var confField = onlineType?.GetField("conf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
var conf = confField?.GetValue(null);
var checkProp = conf?.GetType().GetProperty("checkOnlineSearch", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
if (checkProp?.GetValue(conf) is bool enabled)
return enabled;
}
catch
{
}
return true;
}
private static void OnLog(string message)
{
System.Console.WriteLine(message);
}
}
}