lampac-talks f843f04fd4 chore: initial commit 154.3
Signed-off-by: lampac-talks <lampac-talks@users.noreply.github.com>
2026-01-30 16:23:09 +03:00

196 lines
7.6 KiB
C#

using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using Shared.Models.Online.VkMovie;
namespace Online.Controllers
{
public class VkMovie : BaseOnlineController
{
public VkMovie() : base(AppInit.conf.VkMovie) { }
static readonly int client_id = 52461373;
static string access_token;
static DateTime token_expires;
[HttpGet]
[Route("lite/vkmovie")]
async public Task<ActionResult> Index(string title, string original_title, int year, int serial, bool rjson = false)
{
if (serial == 1)
return OnError();
if (await IsRequestBlocked(rch: true))
return badInitMsg;
if (!await EnsureAnonymToken(init, proxy))
return ShowError("token");
string searchTitle = StringConvert.SearchName(title);
rhubFallback:
var cache = await InvokeCacheResult<CatalogVideo[]>(ipkey($"vkmovie:view:{searchTitle}:{year}"), 20, async e =>
{
string url = $"{init.corsHost()}/method/catalog.getVideoSearchWeb2?v=5.264&client_id={client_id}";
string data = $"screen_ref=search_video_service&input_method=keyboard_search_button&q={HttpUtility.UrlEncode($"{title} {year}")}&access_token={access_token}";
var root = await httpHydra.Post<JObject>(url, data);
if (root == null || !root.ContainsKey("response"))
return e.Fail("response", refresh_proxy: true);
var videos = root["response"]?["catalog_videos"]?.ToObject<CatalogVideo[]>();
if (videos == null)
return e.Fail("catalog_videos");
return e.Success(videos);
});
if (IsRhubFallback(cache))
goto rhubFallback;
return await ContentTpl(cache, () =>
{
var mtpl = new MovieTpl(title, original_title, cache.Value.Length);
foreach (var item in cache.Value
.OrderByDescending(i => i.video?.files?.mp4_2160 != null)
.ThenByDescending(i => i.video?.files?.mp4_1440 != null)
.ThenByDescending(i => i.video?.files?.mp4_1080 != null))
{
var video = item.video;
if (video == null || video.files == null)
continue;
string name = StringConvert.SearchName(video.title);
if (name == null || !name.Contains(searchTitle))
continue;
if (!(name.Contains(year.ToString()) || name.Contains((year + 1).ToString()) || name.Contains((year - 1).ToString())))
continue;
if (video.duration < 3000) // 50 min
continue;
if (name.Contains("трейлер") || name.Contains("trailer") ||
name.Contains("премьера") || name.Contains("обзор") ||
name.Contains("сезон") || name.Contains("сериал") ||
name.Contains("серия") || name.Contains("серий"))
continue;
if (string.IsNullOrEmpty(video.files.mp4_2160)
&& string.IsNullOrEmpty(video.files.mp4_1440)
&& string.IsNullOrEmpty(video.files.mp4_1080)
&& string.IsNullOrEmpty(video.files.mp4_720))
continue;
var streams = new StreamQualityTpl();
void append(string url, string quality)
{
if (!string.IsNullOrEmpty(url))
streams.Append(HostStreamProxy(url), quality);
}
//append(video.files.hls, "auto");
append(video.files.mp4_2160, "2160p");
append(video.files.mp4_1440, "1440p");
append(video.files.mp4_1080, "1080p");
append(video.files.mp4_720, "720p");
append(video.files.mp4_480, "480p");
append(video.files.mp4_360, "360p");
append(video.files.mp4_240, "240p");
append(video.files.mp4_144, "144p");
if (!streams.Any())
continue;
SubtitleTpl? subtitles = null;
if (video.subtitles != null && video.subtitles.Length > 0)
{
var subtitleTpl = new SubtitleTpl(video.subtitles.Length);
foreach (var subtitle in video.subtitles)
{
if (string.IsNullOrEmpty(subtitle?.url))
continue;
string label = subtitle.manifest_name;
if (string.IsNullOrEmpty(label))
label = !string.IsNullOrEmpty(subtitle.title) ? subtitle.title : subtitle.lang;
subtitleTpl.Append(label, HostStreamProxy(subtitle.url));
}
if (!subtitleTpl.IsEmpty)
subtitles = subtitleTpl;
}
mtpl.Append(video.title, streams.Firts().link, streamquality: streams, subtitles: subtitles, headers: HeadersModel.Init(init.headers), vast: init.vast);
}
return mtpl;
});
}
async ValueTask<bool> EnsureAnonymToken(BaseSettings init, System.Net.WebProxy proxy)
{
// If token exists and not expired - ok
if (!string.IsNullOrEmpty(access_token) && token_expires > DateTime.UtcNow)
return true;
var sem = _semaphoreLocks.GetOrAdd("vkmovie:anonym_token", _ => new System.Threading.SemaphoreSlim(1, 1));
try
{
await sem.WaitAsync(TimeSpan.FromSeconds(40));
// double-check after acquiring semaphore
if (!string.IsNullOrEmpty(access_token) && token_expires > DateTime.UtcNow)
return true;
string url = "https://login.vk.com/?act=get_anonym_token";
string postData = $"client_secret=o557NLIkAErNhakXrQ7A&client_id={client_id}&scopes=audio_anonymous%2Cvideo_anonymous%2Cphotos_anonymous%2Cprofile_anonymous&isApiOauthAnonymEnabled=false&version=1&app_id=6287487";
JObject root = null;
try
{
root = await httpHydra.Post<JObject>(url, postData);
}
catch
{
// ignore
}
if (root == null || !root.ContainsKey("data"))
return false;
var data = root["data"];
string token = data?["access_token"]?.ToString();
if (string.IsNullOrEmpty(token))
return false;
access_token = token;
long? expires = data?["expires"]?.ToObject<long?>()
?? data?["expired_at"]?.ToObject<long?>()
?? -1;
// "expires":1760171110 (24ч) | 20ч
token_expires = expires == -1
? DateTime.UtcNow.AddHours(10)
: DateTimeOffset.FromUnixTimeSeconds(expires.Value).UtcDateTime.AddHours(-4);
return true;
}
finally
{
sem.Release();
}
}
}
}