Добавлена подсветка воспроизводимой песни
This commit is contained in:
67
PlaylistShared.Api/Controllers/OgController.cs
Normal file
67
PlaylistShared.Api/Controllers/OgController.cs
Normal 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("\"", "\\\"");
|
||||
}
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
PlaylistShared.Api/ruvector.db
Normal file
BIN
PlaylistShared.Api/ruvector.db
Normal file
Binary file not shown.
Reference in New Issue
Block a user