Merge branch '20263'

This commit is contained in:
baliasnyifeliks 2026-01-14 13:34:40 +02:00
commit b139444cba
16 changed files with 536 additions and 25 deletions

View File

@ -19,6 +19,16 @@ namespace Anihub
{ {
public class AnihubInvoke public class AnihubInvoke
{ {
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init; private OnlinesSettings _init;
private HybridCache _hybridCache; private HybridCache _hybridCache;
private Action<string> _onLog; private Action<string> _onLog;
@ -41,6 +51,9 @@ namespace Anihub
string searchQuery = string.IsNullOrEmpty(title) ? original_title : title; string searchQuery = string.IsNullOrEmpty(title) ? original_title : title;
string searchUrl = $"{_init.apihost}/anime/?search={HttpUtility.UrlEncode(searchQuery)}"; string searchUrl = $"{_init.apihost}/anime/?search={HttpUtility.UrlEncode(searchQuery)}";
if (IsNotAllowedHost(searchUrl))
return null;
string response = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get()); string response = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(response)) if (string.IsNullOrEmpty(response))
@ -75,6 +88,9 @@ namespace Anihub
); );
string sourcesUrl = $"{_init.apihost}/episode-sources/{parsedAnimeId}"; string sourcesUrl = $"{_init.apihost}/episode-sources/{parsedAnimeId}";
if (IsNotAllowedHost(sourcesUrl))
return null;
string response = await Http.Get(sourcesUrl, headers: headers, proxy: _proxyManager.Get()); string response = await Http.Get(sourcesUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(response)) if (string.IsNullOrEmpty(response))
@ -156,6 +172,17 @@ namespace Anihub
return voices; return voices;
} }
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);
}
public async Task<List<SeasonTpl>> GetSeasons(AnihubEpisodeSourcesResponse sources) public async Task<List<SeasonTpl>> GetSeasons(AnihubEpisodeSourcesResponse sources)
{ {
var seasons = new List<SeasonTpl>(); var seasons = new List<SeasonTpl>();

View File

@ -13,12 +13,23 @@ using Shared.Models.Online.Settings;
using Shared.Models; using Shared.Models;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Text;
namespace Anihub namespace Anihub
{ {
[Route("anihub")] [Route("anihub")]
public class AnihubController : BaseOnlineController public class AnihubController : BaseOnlineController
{ {
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
ProxyManager proxyManager; ProxyManager proxyManager;
public AnihubController() public AnihubController()
@ -299,6 +310,9 @@ namespace Anihub
requestUrl = iframeUrl + (iframeUrl.Contains("?") ? "&" : "?") + $"player={host}"; requestUrl = iframeUrl + (iframeUrl.Contains("?") ? "&" : "?") + $"player={host}";
} }
if (IsNotAllowedHost(requestUrl))
return null;
// Створюємо HTTP клієнт з правильними заголовками // Створюємо HTTP клієнт з правильними заголовками
using var httpClient = new HttpClient(); using var httpClient = new HttpClient();
@ -349,5 +363,16 @@ namespace Anihub
return null; 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);
}
} }
} }

View File

@ -6,6 +6,7 @@ using Shared.Models.Online.Settings;
using Shared.Models; using Shared.Models;
using System.Text.Json; using System.Text.Json;
using System.Linq; using System.Linq;
using System.Text;
using AnimeON.Models; using AnimeON.Models;
using Shared.Engine; using Shared.Engine;
@ -13,6 +14,16 @@ namespace AnimeON
{ {
public class AnimeONInvoke public class AnimeONInvoke
{ {
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init; private OnlinesSettings _init;
private HybridCache _hybridCache; private HybridCache _hybridCache;
private Action<string> _onLog; private Action<string> _onLog;
@ -42,6 +53,9 @@ namespace AnimeON
return null; return null;
string searchUrl = $"{_init.host}/api/anime/search?text={System.Web.HttpUtility.UrlEncode(query)}"; string searchUrl = $"{_init.host}/api/anime/search?text={System.Web.HttpUtility.UrlEncode(query)}";
if (IsNotAllowedHost(searchUrl))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {searchUrl}"); _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {searchUrl}");
string searchJson = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get()); string searchJson = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(searchJson)) if (string.IsNullOrEmpty(searchJson))
@ -87,6 +101,9 @@ namespace AnimeON
public async Task<List<FundubModel>> GetFundubs(int animeId) public async Task<List<FundubModel>> GetFundubs(int animeId)
{ {
string fundubsUrl = $"{_init.host}/api/player/{animeId}/translations"; string fundubsUrl = $"{_init.host}/api/player/{animeId}/translations";
if (IsNotAllowedHost(fundubsUrl))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {fundubsUrl}"); _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {fundubsUrl}");
string fundubsJson = await Http.Get(fundubsUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get()); string fundubsJson = await Http.Get(fundubsUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(fundubsJson)) if (string.IsNullOrEmpty(fundubsJson))
@ -112,6 +129,9 @@ namespace AnimeON
public async Task<EpisodeModel> GetEpisodes(int animeId, int playerId, int fundubId) public async Task<EpisodeModel> GetEpisodes(int animeId, int playerId, int fundubId)
{ {
string episodesUrl = $"{_init.host}/api/player/{animeId}/episodes?take=100&skip=-1&playerId={playerId}&translationId={fundubId}"; string episodesUrl = $"{_init.host}/api/player/{animeId}/episodes?take=100&skip=-1&playerId={playerId}&translationId={fundubId}";
if (IsNotAllowedHost(episodesUrl))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {episodesUrl}"); _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {episodesUrl}");
string episodesJson = await Http.Get(episodesUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get()); string episodesJson = await Http.Get(episodesUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(episodesJson)) if (string.IsNullOrEmpty(episodesJson))
@ -131,6 +151,9 @@ namespace AnimeON
new HeadersModel("Referer", "https://animeon.club/") new HeadersModel("Referer", "https://animeon.club/")
}; };
if (IsNotAllowedHost(requestUrl))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {requestUrl}"); _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {requestUrl}");
string html = await Http.Get(requestUrl, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(requestUrl, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) if (string.IsNullOrEmpty(html))
@ -160,6 +183,9 @@ namespace AnimeON
new HeadersModel("Referer", "https://ashdi.vip/") new HeadersModel("Referer", "https://ashdi.vip/")
}; };
if (IsNotAllowedHost(url))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}"); _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}");
string html = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) if (string.IsNullOrEmpty(html))
@ -184,6 +210,9 @@ namespace AnimeON
try try
{ {
string url = $"{_init.host}/api/player/{episodeId}/episode"; string url = $"{_init.host}/api/player/{episodeId}/episode";
if (IsNotAllowedHost(url))
return null;
_onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}"); _onLog($"AnimeON: using proxy {_proxyManager.CurrentProxyIp} for {url}");
string json = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get()); string json = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(json)) if (string.IsNullOrEmpty(json))
@ -217,6 +246,9 @@ namespace AnimeON
if (string.IsNullOrEmpty(url)) if (string.IsNullOrEmpty(url))
return null; return null;
if (IsNotAllowedHost(url))
return null;
if (url.Contains("moonanime.art")) if (url.Contains("moonanime.art"))
return await ParseMoonAnimePage(url); return await ParseMoonAnimePage(url);
@ -226,6 +258,17 @@ namespace AnimeON
return url; return url;
} }
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);
}
public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) 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) if (init != null && init.rhub && rhub != -1)

View File

@ -10,6 +10,7 @@ using Shared;
using Shared.Models.Templates; using Shared.Models.Templates;
using AnimeON.Models; using AnimeON.Models;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Text;
using Shared.Models.Online.Settings; using Shared.Models.Online.Settings;
using Shared.Models; using Shared.Models;
using HtmlAgilityPack; using HtmlAgilityPack;
@ -18,6 +19,16 @@ namespace AnimeON.Controllers
{ {
public class Controller : BaseOnlineController public class Controller : BaseOnlineController
{ {
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
ProxyManager proxyManager; ProxyManager proxyManager;
public Controller() public Controller()
@ -190,6 +201,9 @@ namespace AnimeON.Controllers
async Task<List<FundubModel>> GetFundubs(OnlinesSettings init, int animeId) async Task<List<FundubModel>> GetFundubs(OnlinesSettings init, int animeId)
{ {
string fundubsUrl = $"{init.host}/api/player/{animeId}/translations"; string fundubsUrl = $"{init.host}/api/player/{animeId}/translations";
if (IsNotAllowedHost(fundubsUrl))
return null;
string fundubsJson = await Http.Get(fundubsUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) }); string fundubsJson = await Http.Get(fundubsUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) });
if (string.IsNullOrEmpty(fundubsJson)) if (string.IsNullOrEmpty(fundubsJson))
return null; return null;
@ -214,6 +228,9 @@ namespace AnimeON.Controllers
async Task<EpisodeModel> GetEpisodes(OnlinesSettings init, int animeId, int playerId, int fundubId) async Task<EpisodeModel> GetEpisodes(OnlinesSettings init, int animeId, int playerId, int fundubId)
{ {
string episodesUrl = $"{init.host}/api/player/{animeId}/episodes?take=100&skip=-1&playerId={playerId}&translationId={fundubId}"; string episodesUrl = $"{init.host}/api/player/{animeId}/episodes?take=100&skip=-1&playerId={playerId}&translationId={fundubId}";
if (IsNotAllowedHost(episodesUrl))
return null;
string episodesJson = await Http.Get(episodesUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) }); string episodesJson = await Http.Get(episodesUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) });
if (string.IsNullOrEmpty(episodesJson)) if (string.IsNullOrEmpty(episodesJson))
return null; return null;
@ -237,6 +254,9 @@ namespace AnimeON.Controllers
return null; return null;
string searchUrl = $"{init.host}/api/anime/search?text={HttpUtility.UrlEncode(query)}"; string searchUrl = $"{init.host}/api/anime/search?text={HttpUtility.UrlEncode(query)}";
if (IsNotAllowedHost(searchUrl))
return null;
string searchJson = await Http.Get(searchUrl, headers: headers); string searchJson = await Http.Get(searchUrl, headers: headers);
if (string.IsNullOrEmpty(searchJson)) if (string.IsNullOrEmpty(searchJson))
return null; return null;
@ -326,5 +346,16 @@ namespace AnimeON.Controllers
OnLog("AnimeON Play: return call JSON"); OnLog("AnimeON Play: return call JSON");
return Content(jsonResult, "application/json; charset=utf-8"); return Content(jsonResult, "application/json; charset=utf-8");
} }
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);
}
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
@ -15,6 +16,16 @@ namespace Bamboo
{ {
public class BambooInvoke public class BambooInvoke
{ {
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private readonly OnlinesSettings _init; private readonly OnlinesSettings _init;
private readonly HybridCache _hybridCache; private readonly HybridCache _hybridCache;
private readonly Action<string> _onLog; private readonly Action<string> _onLog;
@ -41,6 +52,9 @@ namespace Bamboo
try try
{ {
string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={HttpUtility.UrlEncode(query)}"; string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={HttpUtility.UrlEncode(query)}";
if (IsNotAllowedHost(searchUrl))
return null;
var headers = new List<HeadersModel>() var headers = new List<HeadersModel>()
{ {
new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("User-Agent", "Mozilla/5.0"),
@ -106,6 +120,9 @@ namespace Bamboo
new HeadersModel("Referer", _init.host) new HeadersModel("Referer", _init.host)
}; };
if (IsNotAllowedHost(href))
return null;
_onLog?.Invoke($"Bamboo series page: {href}"); _onLog?.Invoke($"Bamboo series page: {href}");
string html = await Http.Get(href, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(href, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) if (string.IsNullOrEmpty(html))
@ -180,6 +197,9 @@ namespace Bamboo
new HeadersModel("Referer", _init.host) new HeadersModel("Referer", _init.host)
}; };
if (IsNotAllowedHost(href))
return null;
_onLog?.Invoke($"Bamboo movie page: {href}"); _onLog?.Invoke($"Bamboo movie page: {href}");
string html = await Http.Get(href, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(href, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) if (string.IsNullOrEmpty(html))
@ -281,12 +301,23 @@ namespace Bamboo
return string.Empty; return string.Empty;
if (url.StartsWith("//")) if (url.StartsWith("//"))
return $"https:{url}"; return IsNotAllowedHost($"https:{url}") ? string.Empty : $"https:{url}";
if (url.StartsWith("/")) if (url.StartsWith("/"))
return $"{_init.host}{url}"; return IsNotAllowedHost(_init.host) ? string.Empty : $"{_init.host}{url}";
return url; return IsNotAllowedHost(url) ? string.Empty : url;
}
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);
} }
private static int? ExtractEpisodeNumber(string title) private static int? ExtractEpisodeNumber(string title)

View File

@ -5,6 +5,7 @@ using Shared;
using Shared.Models.Online.Settings; using Shared.Models.Online.Settings;
using Shared.Models; using Shared.Models;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Text;
using HtmlAgilityPack; using HtmlAgilityPack;
using CikavaIdeya.Models; using CikavaIdeya.Models;
using Shared.Engine; using Shared.Engine;
@ -14,6 +15,16 @@ namespace CikavaIdeya
{ {
public class CikavaIdeyaInvoke public class CikavaIdeyaInvoke
{ {
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init; private OnlinesSettings _init;
private HybridCache _hybridCache; private HybridCache _hybridCache;
private Action<string> _onLog; private Action<string> _onLog;
@ -71,6 +82,9 @@ namespace CikavaIdeya
string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(searchTitle)}"; string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(searchTitle)}";
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }; var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) };
if (IsNotAllowedHost(searchUrl))
return null;
var searchHtml = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get()); var searchHtml = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
// Перевіряємо, чи є результати пошуку // Перевіряємо, чи є результати пошуку
if (searchHtml.Contains("На жаль, пошук на сайті не дав жодних результатів")) if (searchHtml.Contains("На жаль, пошук на сайті не дав жодних результатів"))
@ -124,6 +138,9 @@ namespace CikavaIdeya
filmUrl = _init.host + filmUrl; filmUrl = _init.host + filmUrl;
// Отримуємо список епізодів (для фільмів - один епізод, для серіалів - всі епізоди) // Отримуємо список епізодів (для фільмів - один епізод, для серіалів - всі епізоди)
if (IsNotAllowedHost(filmUrl))
return null;
var filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get()); var filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get());
// Перевіряємо, чи не видалено контент // Перевіряємо, чи не видалено контент
if (filmHtml.Contains("Видалено на прохання правовласника")) if (filmHtml.Contains("Видалено на прохання правовласника"))
@ -286,6 +303,9 @@ namespace CikavaIdeya
} }
// Інакше парсимо сторінку // Інакше парсимо сторінку
if (IsNotAllowedHost(url))
return result;
string html = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get()); string html = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get());
var doc = new HtmlDocument(); var doc = new HtmlDocument();
doc.LoadHtml(html); doc.LoadHtml(html);
@ -313,6 +333,9 @@ namespace CikavaIdeya
{ {
_onLog($"GetStreamUrlFromAshdi: trying to get stream URL from {url}"); _onLog($"GetStreamUrlFromAshdi: trying to get stream URL from {url}");
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }; var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") };
if (IsNotAllowedHost(url))
return null;
string html = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
_onLog($"GetStreamUrlFromAshdi: received HTML, length={html.Length}"); _onLog($"GetStreamUrlFromAshdi: received HTML, length={html.Length}");
@ -347,6 +370,17 @@ namespace CikavaIdeya
return null; 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);
}
public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) 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) if (init != null && init.rhub && rhub != -1)

View File

@ -9,6 +9,7 @@ using HtmlAgilityPack;
using Shared; using Shared;
using Shared.Models.Templates; using Shared.Models.Templates;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Text;
using Shared.Models.Online.Settings; using Shared.Models.Online.Settings;
using Shared.Models; using Shared.Models;
using CikavaIdeya.Models; using CikavaIdeya.Models;
@ -17,6 +18,16 @@ namespace CikavaIdeya.Controllers
{ {
public class Controller : BaseOnlineController public class Controller : BaseOnlineController
{ {
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
ProxyManager proxyManager; ProxyManager proxyManager;
public Controller() public Controller()
@ -157,6 +168,9 @@ namespace CikavaIdeya.Controllers
string searchUrl = $"{init.host}/index.php?do=search&subaction=search&story={HttpUtility.UrlEncode(searchTitle)}"; string searchUrl = $"{init.host}/index.php?do=search&subaction=search&story={HttpUtility.UrlEncode(searchTitle)}";
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) }; var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) };
if (IsNotAllowedHost(searchUrl))
return null;
var searchHtml = await Http.Get(searchUrl, headers: headers); var searchHtml = await Http.Get(searchUrl, headers: headers);
// Перевіряємо, чи є результати пошуку // Перевіряємо, чи є результати пошуку
if (searchHtml.Contains("На жаль, пошук на сайті не дав жодних результатів")) if (searchHtml.Contains("На жаль, пошук на сайті не дав жодних результатів"))
@ -210,6 +224,9 @@ namespace CikavaIdeya.Controllers
filmUrl = init.host + filmUrl; filmUrl = init.host + filmUrl;
// Отримуємо список епізодів (для фільмів - один епізод, для серіалів - всі епізоди) // Отримуємо список епізодів (для фільмів - один епізод, для серіалів - всі епізоди)
if (IsNotAllowedHost(filmUrl))
return null;
var filmHtml = await Http.Get(filmUrl, headers: headers); var filmHtml = await Http.Get(filmUrl, headers: headers);
// Перевіряємо, чи не видалено контент // Перевіряємо, чи не видалено контент
if (filmHtml.Contains("Видалено на прохання правовласника")) if (filmHtml.Contains("Видалено на прохання правовласника"))
@ -361,6 +378,9 @@ namespace CikavaIdeya.Controllers
} }
// Інакше парсимо сторінку // Інакше парсимо сторінку
if (IsNotAllowedHost(url))
return result;
string html = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) }); string html = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) });
var doc = new HtmlDocument(); var doc = new HtmlDocument();
doc.LoadHtml(html); doc.LoadHtml(html);
@ -382,5 +402,16 @@ namespace CikavaIdeya.Controllers
} }
return result; return result;
} }
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);
}
} }
} }

View File

@ -1,11 +1,14 @@
# Ukraine online source for Lampac # Ukraine online source for Lampac
## Table of contents - [x] AnimeON
- [x] [RIP] AniHUB
- [Installation](#installation) - [x] BambooUA
- [Auto installation](#auto-installation) - [x] CikavaIdeya
- [Init support](#init-support) - [x] StarLight
- [Donate](#donate) - [x] UAKino
- [x] UAFlix
- [x] UATuTFun
- [x] Unimay
## Installation ## Installation
@ -67,6 +70,7 @@ modules - optional, if not specified, all modules from the repository will be in
"displayindex": 1 "displayindex": 1
} }
``` ```
## Donate ## Donate
Support the author: https://lampame.donatik.me Support the author: https://lampame.donatik.me

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;

View File

@ -1,4 +1,5 @@
using Shared.Models.Base; using Shared.Models.Base;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace StarLight namespace StarLight
@ -9,6 +10,9 @@ namespace StarLight
{ {
var online = new List<(string name, string url, string plugin, int index)>(); var online = new List<(string name, string url, string plugin, int index)>();
if (!string.Equals(original_language, "uk", StringComparison.OrdinalIgnoreCase))
return online;
var init = ModInit.StarLight; var init = ModInit.StarLight;
if (init.enable && !init.rip) if (init.enable && !init.rip)
{ {

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
@ -17,6 +18,16 @@ namespace StarLight
private const string PlayerApi = "https://vcms-api2.starlight.digital/player-api"; private const string PlayerApi = "https://vcms-api2.starlight.digital/player-api";
private const string PlayerReferer = "https://teleportal.ua/"; private const string PlayerReferer = "https://teleportal.ua/";
private const string Language = "ua"; private const string Language = "ua";
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private readonly OnlinesSettings _init; private readonly OnlinesSettings _init;
private readonly HybridCache _hybridCache; private readonly HybridCache _hybridCache;
private readonly Action<string> _onLog; private readonly Action<string> _onLog;
@ -41,6 +52,9 @@ namespace StarLight
return cached; return cached;
string url = $"{_init.host}/{Language}/live-search?q={HttpUtility.UrlEncode(query)}"; string url = $"{_init.host}/{Language}/live-search?q={HttpUtility.UrlEncode(query)}";
if (IsNotAllowedHost(url))
return null;
var headers = new List<HeadersModel>() var headers = new List<HeadersModel>()
{ {
new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("User-Agent", "Mozilla/5.0"),
@ -107,6 +121,9 @@ namespace StarLight
try try
{ {
if (IsNotAllowedHost(href))
return null;
_onLog?.Invoke($"StarLight project: {href}"); _onLog?.Invoke($"StarLight project: {href}");
string payload = await Http.Get(href, headers: headers, proxy: _proxyManager.Get()); string payload = await Http.Get(href, headers: headers, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(payload)) if (string.IsNullOrEmpty(payload))
@ -252,6 +269,9 @@ namespace StarLight
return null; return null;
string url = $"{PlayerApi}/{hash}?referer={HttpUtility.UrlEncode(PlayerReferer)}&lang={Language}"; string url = $"{PlayerApi}/{hash}?referer={HttpUtility.UrlEncode(PlayerReferer)}&lang={Language}";
if (IsNotAllowedHost(url))
return null;
var headers = new List<HeadersModel>() var headers = new List<HeadersModel>()
{ {
new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("User-Agent", "Mozilla/5.0"),
@ -310,9 +330,20 @@ namespace StarLight
return string.Empty; return string.Empty;
if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
return path; return IsNotAllowedHost(path) ? string.Empty : path;
return $"{_init.host}{path}"; return IsNotAllowedHost(_init.host) ? string.Empty : $"{_init.host}{path}";
}
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);
} }
public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1)

View File

@ -1,8 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Security.Authentication;
using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
using HtmlAgilityPack; using HtmlAgilityPack;
@ -19,6 +25,16 @@ namespace UAKino
private const string PlaylistPath = "/engine/ajax/playlists.php"; private const string PlaylistPath = "/engine/ajax/playlists.php";
private const string PlaylistField = "playlist"; private const string PlaylistField = "playlist";
private const string BlacklistRegex = "(/news/)|(/franchise/)"; private const string BlacklistRegex = "(/news/)|(/franchise/)";
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private readonly OnlinesSettings _init; private readonly OnlinesSettings _init;
private readonly HybridCache _hybridCache; private readonly HybridCache _hybridCache;
private readonly Action<string> _onLog; private readonly Action<string> _onLog;
@ -62,7 +78,7 @@ namespace UAKino
}; };
_onLog?.Invoke($"UAKino search: {searchUrl}"); _onLog?.Invoke($"UAKino search: {searchUrl}");
string html = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get()); string html = await GetString(searchUrl, headers);
if (string.IsNullOrEmpty(html)) if (string.IsNullOrEmpty(html))
continue; continue;
@ -147,7 +163,7 @@ namespace UAKino
try try
{ {
_onLog?.Invoke($"UAKino playlist: {url}"); _onLog?.Invoke($"UAKino playlist: {url}");
string payload = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); string payload = await GetString(url, headers);
if (string.IsNullOrEmpty(payload)) if (string.IsNullOrEmpty(payload))
return null; return null;
@ -189,7 +205,7 @@ namespace UAKino
try try
{ {
_onLog?.Invoke($"UAKino movie page: {href}"); _onLog?.Invoke($"UAKino movie page: {href}");
string html = await Http.Get(href, headers: headers, proxy: _proxyManager.Get()); string html = await GetString(href, headers);
if (string.IsNullOrEmpty(html)) if (string.IsNullOrEmpty(html))
return null; return null;
@ -232,7 +248,7 @@ namespace UAKino
try try
{ {
_onLog?.Invoke($"UAKino parse player: {url}"); _onLog?.Invoke($"UAKino parse player: {url}");
string html = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); string html = await GetString(url, headers);
if (string.IsNullOrEmpty(html)) if (string.IsNullOrEmpty(html))
return null; return null;
@ -253,6 +269,50 @@ namespace UAKino
} }
} }
private async Task<string> GetString(string url, List<HeadersModel> headers, int timeoutSeconds = 15)
{
if (IsNotAllowedHost(url))
return null;
var handler = new SocketsHttpHandler
{
AllowAutoRedirect = true,
AutomaticDecompression = DecompressionMethods.Brotli | DecompressionMethods.GZip | DecompressionMethods.Deflate,
SslOptions = new SslClientAuthenticationOptions
{
RemoteCertificateValidationCallback = (_, _, _, _) => true,
EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13
}
};
var proxy = _proxyManager.Get();
if (proxy != null)
{
handler.UseProxy = true;
handler.Proxy = proxy;
}
else
{
handler.UseProxy = false;
}
using var client = new HttpClient(handler);
using var req = new HttpRequestMessage(HttpMethod.Get, url);
if (headers != null)
{
foreach (var h in headers)
req.Headers.TryAddWithoutValidation(h.name, h.val);
}
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(Math.Max(5, timeoutSeconds)));
using var response = await client.SendAsync(req, cts.Token).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
return null;
return await response.Content.ReadAsStringAsync(cts.Token).ConfigureAwait(false);
}
private List<PlaylistItem> ParsePlaylistHtml(string html) private List<PlaylistItem> ParsePlaylistHtml(string html)
{ {
var items = new List<PlaylistItem>(); var items = new List<PlaylistItem>();
@ -357,12 +417,12 @@ namespace UAKino
return string.Empty; return string.Empty;
if (url.StartsWith("//")) if (url.StartsWith("//"))
return $"https:{url}"; return IsNotAllowedHost($"https:{url}") ? string.Empty : $"https:{url}";
if (url.StartsWith("/")) if (url.StartsWith("/"))
return $"{_init.host}{url}"; return IsNotAllowedHost(_init.host) ? string.Empty : $"{_init.host}{url}";
return url; return IsNotAllowedHost(url) ? string.Empty : url;
} }
private static bool LooksLikeDirectStream(string url) private static bool LooksLikeDirectStream(string url)
@ -375,6 +435,17 @@ namespace UAKino
return Regex.IsMatch(url ?? string.Empty, BlacklistRegex, RegexOptions.IgnoreCase); return Regex.IsMatch(url ?? string.Empty, BlacklistRegex, RegexOptions.IgnoreCase);
} }
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);
}
private static bool IsSeriesUrl(string url) private static bool IsSeriesUrl(string url)
{ {
return url.Contains("/seriesss/") || url.Contains("/anime-series/") || url.Contains("/cartoonseries/"); return url.Contains("/seriesss/") || url.Contains("/anime-series/") || url.Contains("/cartoonseries/");

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
@ -15,6 +16,16 @@ namespace UaTUT
{ {
public class UaTUTInvoke public class UaTUTInvoke
{ {
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init; private OnlinesSettings _init;
private HybridCache _hybridCache; private HybridCache _hybridCache;
private Action<string> _onLog; private Action<string> _onLog;
@ -63,6 +74,9 @@ namespace UaTUT
string url = $"{searchUrl}?q={HttpUtility.UrlEncode(query)}"; string url = $"{searchUrl}?q={HttpUtility.UrlEncode(query)}";
_onLog($"UaTUT searching: {url}"); _onLog($"UaTUT searching: {url}");
if (IsNotAllowedHost(url))
return null;
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") }; var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") };
var response = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); var response = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
@ -89,6 +103,9 @@ namespace UaTUT
string url = $"{_init.apihost}/{movieId}"; string url = $"{_init.apihost}/{movieId}";
_onLog($"UaTUT getting movie page: {url}"); _onLog($"UaTUT getting movie page: {url}");
if (IsNotAllowedHost(url))
return null;
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") }; var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") };
var response = await Http.Get(url, headers: headers, proxy: _proxyManager.Get()); var response = await Http.Get(url, headers: headers, proxy: _proxyManager.Get());
@ -130,6 +147,9 @@ namespace UaTUT
{ {
_onLog($"UaTUT getting player data from: {playerUrl}"); _onLog($"UaTUT getting player data from: {playerUrl}");
if (IsNotAllowedHost(playerUrl))
return null;
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") }; var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") };
var response = await Http.Get(playerUrl, headers: headers, proxy: _proxyManager.Get()); var response = await Http.Get(playerUrl, headers: headers, proxy: _proxyManager.Get());
@ -145,6 +165,17 @@ namespace UaTUT
} }
} }
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);
}
private PlayerData ParsePlayerData(string playerHtml) private PlayerData ParsePlayerData(string playerHtml)
{ {
try try

View File

@ -10,6 +10,7 @@ using HtmlAgilityPack;
using Shared; using Shared;
using Shared.Models.Templates; using Shared.Models.Templates;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Text;
using Shared.Models.Online.Settings; using Shared.Models.Online.Settings;
using Shared.Models; using Shared.Models;
using Uaflix.Models; using Uaflix.Models;
@ -19,6 +20,16 @@ namespace Uaflix.Controllers
public class Controller : BaseOnlineController public class Controller : BaseOnlineController
{ {
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
ProxyManager proxyManager; ProxyManager proxyManager;
public Controller() public Controller()
@ -50,6 +61,9 @@ namespace Uaflix.Controllers
string searchUrl = $"{init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(filmTitle)}"; string searchUrl = $"{init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(filmTitle)}";
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) }; var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", init.host) };
if (IsNotAllowedHost(searchUrl))
return OnError("uaflix", proxyManager);
var searchHtml = await Http.Get(searchUrl, headers: headers, proxy: proxyManager.Get(), timeoutSeconds: 10); var searchHtml = await Http.Get(searchUrl, headers: headers, proxy: proxyManager.Get(), timeoutSeconds: 10);
// Швидка перевірка наявності результатів без повного парсингу // Швидка перевірка наявності результатів без повного парсингу
@ -282,7 +296,8 @@ namespace Uaflix.Controllers
s: s.ToString(), s: s.ToString(),
e: ep.Number.ToString(), e: ep.Number.ToString(),
link: accsArgs(callUrl), link: accsArgs(callUrl),
method: "call" method: "call",
streamlink: accsArgs($"{callUrl}&play=true")
); );
} }
else else
@ -329,6 +344,15 @@ namespace Uaflix.Controllers
} }
} }
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);
}
} }
} }

View File

@ -14,11 +14,22 @@ using Shared.Models.Templates;
using System.Net; using System.Net;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System.Text;
namespace Uaflix namespace Uaflix
{ {
public class UaflixInvoke public class UaflixInvoke
{ {
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init; private OnlinesSettings _init;
private HybridCache _hybridCache; private HybridCache _hybridCache;
private Action<string> _onLog; private Action<string> _onLog;
@ -90,6 +101,9 @@ namespace Uaflix
} }
} }
if (IsNotAllowedHost(requestUrl))
return null;
string html = await Http.Get(requestUrl, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(requestUrl, headers: headers, proxy: _proxyManager.Get());
// Знайти JSON у new Playerjs({file:'...'}) // Знайти JSON у new Playerjs({file:'...'})
@ -201,6 +215,9 @@ namespace Uaflix
try try
{ {
if (IsNotAllowedHost(iframeUrl))
return (null, null);
string html = await Http.Get(iframeUrl, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(iframeUrl, headers: headers, proxy: _proxyManager.Get());
// Знайти file:"url" // Знайти file:"url"
@ -235,6 +252,9 @@ namespace Uaflix
try try
{ {
if (IsNotAllowedHost(iframeUrl))
return (null, null);
string html = await Http.Get(iframeUrl, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(iframeUrl, headers: headers, proxy: _proxyManager.Get());
// Шукаємо Playerjs конфігурацію з file параметром // Шукаємо Playerjs конфігурацію з file параметром
@ -341,6 +361,9 @@ namespace Uaflix
new HeadersModel("Referer", _init.host) new HeadersModel("Referer", _init.host)
}; };
if (IsNotAllowedHost(firstEpisode.url))
continue;
string html = await Http.Get(firstEpisode.url, headers: headers, proxy: _proxyManager.Get()); string html = await Http.Get(firstEpisode.url, headers: headers, proxy: _proxyManager.Get());
var doc = new HtmlDocument(); var doc = new HtmlDocument();
@ -500,6 +523,8 @@ namespace Uaflix
return null; return null;
} }
NormalizeUaflixVoiceNames(structure);
// Edge Case 9: Перевірка наявності епізодів у озвучках // Edge Case 9: Перевірка наявності епізодів у озвучках
bool hasEpisodes = structure.Voices.Values.Any(v => v.Seasons.Values.Any(s => s.Any())); bool hasEpisodes = structure.Voices.Values.Any(v => v.Seasons.Values.Any(s => s.Any()));
if (!hasEpisodes) if (!hasEpisodes)
@ -555,6 +580,9 @@ namespace Uaflix
string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(filmTitle)}"; string searchUrl = $"{_init.host}/index.php?do=search&subaction=search&story={System.Web.HttpUtility.UrlEncode(filmTitle)}";
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }; var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) };
if (IsNotAllowedHost(searchUrl))
return null;
var searchHtml = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get()); var searchHtml = await Http.Get(searchUrl, headers: headers, proxy: _proxyManager.Get());
var doc = new HtmlDocument(); var doc = new HtmlDocument();
doc.LoadHtml(searchHtml); doc.LoadHtml(searchHtml);
@ -647,6 +675,9 @@ namespace Uaflix
try try
{ {
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }; var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) };
if (IsNotAllowedHost(filmUrl))
return null;
var filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get()); var filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get());
var doc = new HtmlDocument(); var doc = new HtmlDocument();
doc.LoadHtml(filmHtml); doc.LoadHtml(filmHtml);
@ -722,6 +753,9 @@ namespace Uaflix
try try
{ {
var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }; var headers = new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) };
if (IsNotAllowedHost(filmUrl))
return null;
var filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get()); var filmHtml = await Http.Get(filmUrl, headers: headers, proxy: _proxyManager.Get());
var filmDoc = new HtmlDocument(); var filmDoc = new HtmlDocument();
filmDoc.LoadHtml(filmHtml); filmDoc.LoadHtml(filmHtml);
@ -756,7 +790,11 @@ namespace Uaflix
seasonUrls.Add(filmUrl); seasonUrls.Add(filmUrl);
} }
var seasonTasks = seasonUrls.Select(url => Http.Get(url, headers: headers, proxy: _proxyManager.Get()).AsTask()); var safeSeasonUrls = seasonUrls.Where(url => !IsNotAllowedHost(url)).ToList();
if (safeSeasonUrls.Count == 0)
return null;
var seasonTasks = safeSeasonUrls.Select(url => Http.Get(url, headers: headers, proxy: _proxyManager.Get()).AsTask());
var seasonPagesHtml = await Task.WhenAll(seasonTasks); var seasonPagesHtml = await Task.WhenAll(seasonTasks);
foreach (var html in seasonPagesHtml) foreach (var html in seasonPagesHtml)
@ -817,6 +855,9 @@ namespace Uaflix
var result = new Uaflix.Models.PlayResult() { streams = new List<(string, string)>() }; var result = new Uaflix.Models.PlayResult() { streams = new List<(string, string)>() };
try try
{ {
if (IsNotAllowedHost(url))
return result;
string html = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get()); string html = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", _init.host) }, proxy: _proxyManager.Get());
var doc = new HtmlDocument(); var doc = new HtmlDocument();
doc.LoadHtml(html); doc.LoadHtml(html);
@ -888,9 +929,44 @@ namespace Uaflix
return result; return result;
} }
private void NormalizeUaflixVoiceNames(SerialAggregatedStructure structure)
{
const string baseName = "Uaflix";
const string zetName = "Uaflix #2";
const string ashdiName = "Uaflix #3";
if (structure == null || structure.Voices == null || structure.Voices.Count == 0)
return;
bool hasBase = structure.Voices.ContainsKey(baseName);
bool hasZet = structure.Voices.ContainsKey(zetName);
bool hasAshdi = structure.Voices.ContainsKey(ashdiName);
if (hasBase)
return;
if (hasZet && !hasAshdi)
{
var voice = structure.Voices[zetName];
voice.DisplayName = baseName;
structure.Voices.Remove(zetName);
structure.Voices[baseName] = voice;
}
else if (hasAshdi && !hasZet)
{
var voice = structure.Voices[ashdiName];
voice.DisplayName = baseName;
structure.Voices.Remove(ashdiName);
structure.Voices[baseName] = voice;
}
}
async Task<List<(string link, string quality)>> ParseAllZetvideoSources(string iframeUrl) async Task<List<(string link, string quality)>> ParseAllZetvideoSources(string iframeUrl)
{ {
var result = new List<(string link, string quality)>(); var result = new List<(string link, string quality)>();
if (IsNotAllowedHost(iframeUrl))
return result;
var html = await Http.Get(iframeUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://zetvideo.net/") }, proxy: _proxyManager.Get()); var html = await Http.Get(iframeUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://zetvideo.net/") }, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) return result; if (string.IsNullOrEmpty(html)) return result;
@ -922,6 +998,9 @@ namespace Uaflix
async Task<List<(string link, string quality)>> ParseAllAshdiSources(string iframeUrl) async Task<List<(string link, string quality)>> ParseAllAshdiSources(string iframeUrl)
{ {
var result = new List<(string link, string quality)>(); var result = new List<(string link, string quality)>();
if (IsNotAllowedHost(iframeUrl))
return result;
var html = await Http.Get(iframeUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }, proxy: _proxyManager.Get()); var html = await Http.Get(iframeUrl, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }, proxy: _proxyManager.Get());
if (string.IsNullOrEmpty(html)) return result; if (string.IsNullOrEmpty(html)) return result;
@ -941,7 +1020,11 @@ namespace Uaflix
async Task<SubtitleTpl?> GetAshdiSubtitles(string id) async Task<SubtitleTpl?> GetAshdiSubtitles(string id)
{ {
var html = await Http.Get($"https://ashdi.vip/vod/{id}", headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }, proxy: _proxyManager.Get()); string url = $"https://ashdi.vip/vod/{id}";
if (IsNotAllowedHost(url))
return null;
var html = await Http.Get(url, headers: new List<HeadersModel>() { new HeadersModel("User-Agent", "Mozilla/5.0"), new HeadersModel("Referer", "https://ashdi.vip/") }, proxy: _proxyManager.Get());
string subtitle = new Regex("subtitle(\")?:\"([^\"]+)\"").Match(html).Groups[2].Value; string subtitle = new Regex("subtitle(\")?:\"([^\"]+)\"").Match(html).Groups[2].Value;
if (!string.IsNullOrEmpty(subtitle)) if (!string.IsNullOrEmpty(subtitle))
{ {
@ -970,6 +1053,17 @@ namespace Uaflix
return TimeSpan.FromMinutes(ctime); return TimeSpan.FromMinutes(ctime);
} }
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);
}
/// <summary> /// <summary>
/// Оновлений метод кешування згідно стандарту Lampac /// Оновлений метод кешування згідно стандарту Lampac
/// </summary> /// </summary>

View File

@ -8,11 +8,22 @@ using System.Linq;
using Unimay.Models; using Unimay.Models;
using Shared.Engine; using Shared.Engine;
using System.Net; using System.Net;
using System.Text;
namespace Unimay namespace Unimay
{ {
public class UnimayInvoke public class UnimayInvoke
{ {
private static readonly HashSet<string> NotAllowedHosts =
new HashSet<string>(
new[]
{
"c3ZpdGFubW92aWU=",
"cG9ydGFsLXR2",
}
.Select(base64 => Encoding.UTF8.GetString(Convert.FromBase64String(base64))),
StringComparer.OrdinalIgnoreCase
);
private OnlinesSettings _init; private OnlinesSettings _init;
private ProxyManager _proxyManager; private ProxyManager _proxyManager;
private HybridCache _hybridCache; private HybridCache _hybridCache;
@ -37,6 +48,9 @@ namespace Unimay
string searchQuery = System.Web.HttpUtility.UrlEncode(title ?? original_title ?? ""); string searchQuery = System.Web.HttpUtility.UrlEncode(title ?? original_title ?? "");
string searchUrl = $"{_init.host}/release/search?page=0&page_size=10&title={searchQuery}"; string searchUrl = $"{_init.host}/release/search?page=0&page_size=10&title={searchQuery}";
if (IsNotAllowedHost(searchUrl))
return null;
var headers = httpHeaders(_init); var headers = httpHeaders(_init);
SearchResponse root = await Http.Get<SearchResponse>(searchUrl, timeoutSeconds: 8, proxy: _proxyManager.Get(), headers: headers); SearchResponse root = await Http.Get<SearchResponse>(searchUrl, timeoutSeconds: 8, proxy: _proxyManager.Get(), headers: headers);
@ -67,6 +81,9 @@ namespace Unimay
{ {
string releaseUrl = $"{_init.host}/release?code={code}"; string releaseUrl = $"{_init.host}/release?code={code}";
if (IsNotAllowedHost(releaseUrl))
return null;
var headers = httpHeaders(_init); var headers = httpHeaders(_init);
ReleaseResponse root = await Http.Get<ReleaseResponse>(releaseUrl, timeoutSeconds: 8, proxy: _proxyManager.Get(), headers: headers); ReleaseResponse root = await Http.Get<ReleaseResponse>(releaseUrl, timeoutSeconds: 8, proxy: _proxyManager.Get(), headers: headers);
@ -158,6 +175,18 @@ namespace Unimay
new HeadersModel("Accept", "application/json") new HeadersModel("Accept", "application/json")
}; };
} }
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);
}
public static TimeSpan cacheTime(int multiaccess, int home = 5, int mikrotik = 2, OnlinesSettings init = null, int rhub = -1) 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) if (init != null && init.rhub && rhub != -1)