Добавлена подсветка воспроизводимой песни

This commit is contained in:
FrigaT
2026-05-22 00:07:26 +03:00
parent 9139d8ecfe
commit efe1c3c2dd
23 changed files with 362 additions and 57 deletions

View File

@@ -0,0 +1,67 @@
using Microsoft.AspNetCore.Mvc;
using PlaylistShared.Api.Services;
namespace PlaylistShared.Api.Controllers;
[ApiController]
[Route("shared")]
public class OgController : ControllerBase
{
private readonly SharedPlaylistService _sharedService;
private readonly string _clientBaseUrl;
public OgController(SharedPlaylistService sharedService, IConfiguration configuration)
{
_sharedService = sharedService;
_clientBaseUrl = configuration["Client:BaseUrl"]?.TrimEnd('/') ?? "";
}
[HttpGet("{token}")]
[Produces("text/html")]
public async Task<ContentResult> GetOgPage(string token)
{
var entity = await _sharedService.GetEntityByTokenAsync(token);
var pwaUrl = $"{_clientBaseUrl}/shared/{token}";
string title = entity?.Title ?? "Playlist Share";
string description = entity != null
? $"Слушайте плейлист «{entity.Title}» на Playlist Share"
: "Совместные плейлисты Яндекс.Музыки";
string imageUrl = !string.IsNullOrEmpty(entity?.CoverUrl) ? entity.CoverUrl : "";
var html = $"""
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{HtmlEncode(title)}</title>
<meta property="og:type" content="music.playlist" />
<meta property="og:title" content="{HtmlEncode(title)}" />
<meta property="og:description" content="{HtmlEncode(description)}" />
<meta property="og:url" content="{HtmlEncode(pwaUrl)}" />
{(string.IsNullOrEmpty(imageUrl) ? "" : $"""<meta property="og:image" content="{HtmlEncode(imageUrl)}" />""")}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{HtmlEncode(title)}" />
<meta name="twitter:description" content="{HtmlEncode(description)}" />
{(string.IsNullOrEmpty(imageUrl) ? "" : $"""<meta name="twitter:image" content="{HtmlEncode(imageUrl)}" />""")}
<meta http-equiv="refresh" content="0;url={HtmlEncode(pwaUrl)}" />
<script>window.location.replace("{JsEncode(pwaUrl)}");</script>
</head>
<body>
<p>Перенаправление на <a href="{HtmlEncode(pwaUrl)}">{HtmlEncode(title)}</a></p>
</body>
</html>
""";
return Content(html, "text/html; charset=utf-8");
}
private static string HtmlEncode(string s) =>
System.Web.HttpUtility.HtmlAttributeEncode(s);
private static string JsEncode(string s) =>
s.Replace("\\", "\\\\").Replace("'", "\\'").Replace("\"", "\\\"");
}

View File

@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
@@ -51,6 +52,14 @@ public class Program
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.Cookie.SameSite = SameSiteMode.Lax;
options.Cookie.MaxAge = TimeSpan.FromDays(30); // persistent across browser restarts
});
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.KnownNetworks.Clear(); // trust all proxies in Docker network
options.KnownProxies.Clear();
});
// JWT
@@ -129,6 +138,7 @@ public class Program
app.MapOpenApi();
app.UseForwardedHeaders();
app.UseCors("Production");
if (!app.Environment.IsDevelopment())

View File

@@ -44,10 +44,10 @@ public class YandexAuthService
internal async Task<YandexAuthQr> GenerateQrAsync(ApplicationUser user)
{
var qr = await Api.Passport.GetAuthQRLinkAsync();
var trackId = Service.Client.AuthStorage.AuthToken.TrackId;
var csrfToken = Service.Client.AuthStorage.AuthToken.CsfrToken;
var headerProcessUuid = Service.Client.AuthStorage.HeaderToken.ProcessUuid;
var headerCsrfToken = Service.Client.AuthStorage.HeaderToken.CsfrToken;
var trackId = Service.Client.AuthStorage.AuthToken?.TrackId;
var csrfToken = Service.Client.AuthStorage.AuthToken?.CsfrToken;
var headerProcessUuid = Service.Client.AuthStorage.HeaderToken?.ProcessUuid;
var headerCsrfToken = Service.Client.AuthStorage.HeaderToken?.CsfrToken;
if (string.IsNullOrEmpty(qr))
throw new Exception("Не удалось получить QR-ссылку");
@@ -93,6 +93,8 @@ public class YandexAuthService
Service.Client.AuthStorage.AuthToken.CsfrToken = session.CsrfToken ?? "";
Service.Client.AuthStorage.AuthToken.TrackId = session.TrackId ?? "";
if (Service.Client.AuthStorage.HeaderToken is null)
Service.Client.AuthStorage.HeaderToken = new();
Service.Client.AuthStorage.HeaderToken.CsfrToken = session.HeaderCsrfToken ?? "";
Service.Client.AuthStorage.HeaderToken.ProcessUuid = session.HeaderProcessId ?? "";
@@ -131,15 +133,16 @@ public class YandexAuthService
private void RestoreCookies(CookieContainer container, string serializedCookies)
{
var cookies = JsonSerializer.Deserialize<List<CookieData>>(serializedCookies);
if (cookies == null) return;
foreach (var c in cookies)
container.Add(new Cookie(c.Name, c.Value, c.Path, c.Domain));
}
private class CookieData
{
public string Name { get; set; }
public string Value { get; set; }
public string Domain { get; set; }
public string Path { get; set; }
public string Name { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
public string Domain { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
}
}

Binary file not shown.