mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-10 16:08:39 -05:00
Major Features: - Spotify playlist injection with missing tracks search - Transparent proxy authentication system - WebSocket session management for external tracks - Manual track mapping and favorites system - Lyrics support (Spotify + LRCLib) with prefetching - Admin dashboard with analytics and configuration - Performance optimizations with health checks and endpoint racing - Comprehensive caching and memory management Performance Improvements: - Quick health checks (3s timeout) before trying endpoints - Health check results cached for 30 seconds - 5 minute timeout for large artist responses - Background Odesli conversion after streaming starts - Parallel lyrics prefetching - Endpoint benchmarking and racing - 16 SquidWTF endpoints with load balancing Reliability: - Automatic endpoint fallback and failover - Token expiration handling - Concurrent request optimization - Memory leak fixes - Proper session cleanup User Experience: - Web UI for configuration and playlist management - Real-time progress tracking - API analytics dashboard - Manual track mapping interface - Playlist statistics and health monitoring
77 lines
2.4 KiB
C#
77 lines
2.4 KiB
C#
using Microsoft.AspNetCore.StaticFiles;
|
|
using Microsoft.Extensions.FileProviders;
|
|
|
|
namespace allstarr.Middleware;
|
|
|
|
/// <summary>
|
|
/// Middleware that only serves static files on the admin port (5275).
|
|
/// This keeps the admin UI isolated from the main proxy port.
|
|
/// </summary>
|
|
public class AdminStaticFilesMiddleware
|
|
{
|
|
private readonly RequestDelegate _next;
|
|
private readonly IWebHostEnvironment _env;
|
|
private const int AdminPort = 5275;
|
|
|
|
public AdminStaticFilesMiddleware(
|
|
RequestDelegate next,
|
|
IWebHostEnvironment env)
|
|
{
|
|
_next = next;
|
|
_env = env;
|
|
}
|
|
|
|
public async Task InvokeAsync(HttpContext context)
|
|
{
|
|
var port = context.Connection.LocalPort;
|
|
|
|
if (port == AdminPort)
|
|
{
|
|
var path = context.Request.Path.Value ?? "/";
|
|
|
|
// Serve index.html for root path
|
|
if (path == "/" || path == "/index.html")
|
|
{
|
|
var indexPath = Path.Combine(_env.WebRootPath, "index.html");
|
|
if (File.Exists(indexPath))
|
|
{
|
|
context.Response.ContentType = "text/html";
|
|
await context.Response.SendFileAsync(indexPath);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Try to serve static file from wwwroot
|
|
var filePath = Path.Combine(_env.WebRootPath, path.TrimStart('/'));
|
|
if (File.Exists(filePath))
|
|
{
|
|
var contentType = GetContentType(filePath);
|
|
context.Response.ContentType = contentType;
|
|
await context.Response.SendFileAsync(filePath);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Not admin port or file not found - continue pipeline
|
|
await _next(context);
|
|
}
|
|
|
|
private static string GetContentType(string filePath)
|
|
{
|
|
var ext = Path.GetExtension(filePath).ToLowerInvariant();
|
|
return ext switch
|
|
{
|
|
".html" => "text/html",
|
|
".css" => "text/css",
|
|
".js" => "application/javascript",
|
|
".json" => "application/json",
|
|
".png" => "image/png",
|
|
".jpg" or ".jpeg" => "image/jpeg",
|
|
".gif" => "image/gif",
|
|
".svg" => "image/svg+xml",
|
|
".ico" => "image/x-icon",
|
|
_ => "application/octet-stream"
|
|
};
|
|
}
|
|
}
|