BililiveRecorder/BililiveRecorder.Web/DynamicHtmlController.cs
2022-08-27 15:50:38 +08:00

99 lines
3.5 KiB
C#

using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using AngleSharp.Html;
using AngleSharp.Html.Parser;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.FileProviders;
using NUglify;
namespace BililiveRecorder.Web
{
[Controller]
[ApiExplorerSettings(IgnoreApi = true)]
public sealed class DynamicHtmlController : Controller
{
private static readonly MinifyMarkupFormatter formatter = new MinifyMarkupFormatter
{
ShouldKeepEmptyAttributes = true,
};
private static string? cachedIndexHtml;
private readonly CompositeFileProvider fileProvider;
public DynamicHtmlController(CompositeFileProvider fileProvider)
{
this.fileProvider = fileProvider ?? throw new ArgumentNullException(nameof(fileProvider));
}
[Route("/", Name = "Home Page"), HttpGet]
public ActionResult GetHomePage()
{
if (cachedIndexHtml is null)
{
using var file = this.fileProvider.GetFileInfo("/index.html").CreateReadStream();
using var reader = new StreamReader(file, Encoding.UTF8);
var html = reader.ReadToEnd();
cachedIndexHtml = html
.Replace("__VERSION__", GitVersionInformation.FullSemVer)
.Replace("__FULL_VERSION__", GitVersionInformation.InformationalVersion)
;
}
return this.Content(cachedIndexHtml, "text/html", Encoding.UTF8);
}
[Route("/ui/", Name = "WebUI Html"), HttpGet]
public async Task GetWebUIAsync()
{
var parser = new HtmlParser();
var fileInfo = this.fileProvider.GetFileInfo("/ui/index.html");
using var injectionScriptStream = new StreamReader(this.fileProvider.GetFileInfo(".webui_injection.js").CreateReadStream());
var scriptContent = await injectionScriptStream.ReadToEndAsync();
using var stream = fileInfo.CreateReadStream();
using var document = await parser.ParseDocumentAsync(stream).ConfigureAwait(false);
var spaPath = this.HttpContext.Items.ContainsKey("webui-spa-path") ? ((PathString)this.HttpContext.Items["webui-spa-path"]!) : this.Request.Path;
spaPath.StartsWithSegments("/ui", out var remaining);
var head = document.Head!;
var template = document.CreateElement("template");
template.Id = "delayed-init";
head.AppendChild(template);
var scripts = document.QuerySelectorAll("script[type='module']");
var css = document.QuerySelectorAll("link[rel='stylesheet']");
foreach (var script in scripts)
{
script.Remove();
template.AppendChild(script);
}
foreach (var node in css)
{
node.Remove();
template.AppendChild(node);
}
var initScript = document.CreateElement("script");
initScript.TextContent = Uglify.Js(scriptContent).Code;
initScript.SetAttribute("data-href", remaining);
head.AppendChild(initScript);
this.Response.StatusCode = 200;
this.Response.ContentType = "text/html; encoding=utf-8";
using var writer = new StreamWriter(this.Response.Body);
document.ToHtml(writer, formatter);
}
}
}