From 707f51c52c518661f61f4e9fec56bc9aae895e9f Mon Sep 17 00:00:00 2001 From: baliasnyifeliks Date: Tue, 13 Jan 2026 09:21:26 +0200 Subject: [PATCH] feat(AnimeON): add support for Ashdi player and episode stream resolution - Add ParseAshdiPage method to extract video URLs from Ashdi pages - Implement ResolveEpisodeStream to fetch streams via API endpoint - Add ResolveVideoUrl method to handle different video URL types - Update Controller to handle new player types and stream resolution - Add episode_id parameter to play endpoint for direct episode streaming BREAKING CHANGE: The play endpoint now accepts both url and episode_id parameters --- AnimeON/AnimeONInvoke.cs | 78 +++++++++++++++++++++++++++++++++++++++- AnimeON/Controller.cs | 44 +++++++++++++++-------- 2 files changed, 107 insertions(+), 15 deletions(-) diff --git a/AnimeON/AnimeONInvoke.cs b/AnimeON/AnimeONInvoke.cs index 4f89bfa..f268c43 100644 --- a/AnimeON/AnimeONInvoke.cs +++ b/AnimeON/AnimeONInvoke.cs @@ -150,6 +150,82 @@ namespace AnimeON return null; } + public async Task ParseAshdiPage(string url) + { + try + { + var headers = new List() + { + new HeadersModel("User-Agent", "Mozilla/5.0"), + new HeadersModel("Referer", _init.host) + }; + + _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}"); + string html = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); + if (string.IsNullOrEmpty(html)) + return null; + + var match = System.Text.RegularExpressions.Regex.Match(html, @"file:\s*""([^""]+)"""); + if (match.Success) + { + return match.Groups[1].Value; + } + } + catch (Exception ex) + { + _onLog($"AnimeON ParseAshdiPage error: {ex.Message}"); + } + + return null; + } + + public async Task ResolveEpisodeStream(int episodeId) + { + try + { + string url = $"{_init.host}/api/player/{episodeId}/episode"; + _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}"); + string json = await Http.Get(url, headers: new List() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get()); + if (string.IsNullOrEmpty(json)) + return null; + + using var doc = JsonDocument.Parse(json); + var root = doc.RootElement; + if (root.TryGetProperty("fileUrl", out var fileProp)) + { + string fileUrl = fileProp.GetString(); + if (!string.IsNullOrEmpty(fileUrl)) + return fileUrl; + } + + if (root.TryGetProperty("videoUrl", out var videoProp)) + { + string videoUrl = videoProp.GetString(); + return await ResolveVideoUrl(videoUrl); + } + } + catch (Exception ex) + { + _onLog($"AnimeON ResolveEpisodeStream error: {ex.Message}"); + } + + return null; + } + + public async Task ResolveVideoUrl(string url) + { + if (string.IsNullOrEmpty(url)) + return null; + + if (url.Contains("moonanime.art")) + return await ParseMoonAnimePage(url); + + if (url.Contains("ashdi.vip/vod")) + return await ParseAshdiPage(url); + + return url; + } + public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) { if (init != null && init.rhub && rhub != -1) @@ -230,4 +306,4 @@ namespace AnimeON } } } -} \ No newline at end of file +} diff --git a/AnimeON/Controller.cs b/AnimeON/Controller.cs index b17f787..a828598 100644 --- a/AnimeON/Controller.cs +++ b/AnimeON/Controller.cs @@ -99,18 +99,25 @@ namespace AnimeON.Controllers string episodeStr = ep.Number.ToString(); string streamLink = !string.IsNullOrEmpty(ep.Hls) ? ep.Hls : ep.VideoUrl; + bool needsResolve = selectedVoiceInfo.PlayerType == "moon" || selectedVoiceInfo.PlayerType == "ashdi"; + + if (string.IsNullOrEmpty(streamLink) && ep.EpisodeId > 0) + { + string callUrl = $"{host}/animeon/play?episode_id={ep.EpisodeId}"; + episode_tpl.Append(episodeName, title ?? original_title, seasonStr, episodeStr, accsArgs(callUrl), "call"); + continue; + } + if (string.IsNullOrEmpty(streamLink)) continue; - if (selectedVoiceInfo.PlayerType == "moon") + if (needsResolve || streamLink.Contains("moonanime.art") || streamLink.Contains("ashdi.vip/vod")) { - // method=call з accsArgs(callUrl) string callUrl = $"{host}/animeon/play?url={HttpUtility.UrlEncode(streamLink)}"; episode_tpl.Append(episodeName, title ?? original_title, seasonStr, episodeStr, accsArgs(callUrl), "call"); } else { - // Пряме відтворення через HostStreamProxy(init, accsArgs(streamLink)) string playUrl = HostStreamProxy(init, accsArgs(streamLink)); episode_tpl.Append(episodeName, title ?? original_title, seasonStr, episodeStr, playUrl); } @@ -158,7 +165,8 @@ namespace AnimeON.Controllers string translationName = $"[{player.Name}] {fundub.Fundub.Name}"; - if (player.Name?.ToLower() == "moon" && streamLink.Contains("moonanime.art/iframe/")) + bool needsResolve = player.Name?.ToLower() == "moon" || player.Name?.ToLower() == "ashdi"; + if (needsResolve || streamLink.Contains("moonanime.art/iframe/") || streamLink.Contains("ashdi.vip/vod")) { string callUrl = $"{host}/animeon/play?url={HttpUtility.UrlEncode(streamLink)}"; tpl.Append(translationName, accsArgs(callUrl), "call"); @@ -271,25 +279,33 @@ namespace AnimeON.Controllers } [HttpGet("animeon/play")] - public async Task Play(string url) + public async Task Play(string url, int episode_id = 0) { - if (string.IsNullOrEmpty(url)) - { - OnLog("AnimeON Play: empty url"); - return OnError("animeon", proxyManager); - } - var init = await loadKit(ModInit.AnimeON); if (!init.enable) return Forbid(); var invoke = new AnimeONInvoke(init, hybridCache, OnLog, proxyManager); - OnLog($"AnimeON Play: url={url}"); - string streamLink = await invoke.ParseMoonAnimePage(url); + OnLog($"AnimeON Play: url={url}, episode_id={episode_id}"); + + string streamLink = null; + if (episode_id > 0) + { + streamLink = await invoke.ResolveEpisodeStream(episode_id); + } + else if (!string.IsNullOrEmpty(url)) + { + streamLink = await invoke.ResolveVideoUrl(url); + } + else + { + OnLog("AnimeON Play: empty url"); + return OnError("animeon", proxyManager); + } if (string.IsNullOrEmpty(streamLink)) { - OnLog("AnimeON Play: cannot extract stream from iframe"); + OnLog("AnimeON Play: cannot extract stream"); return OnError("animeon", proxyManager); }