diff --git a/allstarr/Controllers/JellyfinController.cs b/allstarr/Controllers/JellyfinController.cs
index a082c53..505f117 100644
--- a/allstarr/Controllers/JellyfinController.cs
+++ b/allstarr/Controllers/JellyfinController.cs
@@ -1670,6 +1670,64 @@ public class JellyfinController : ControllerBase
#region Playback Session Reporting
+ #region Session Management
+
+ ///
+ /// Reports session capabilities. Required for Jellyfin to track active sessions.
+ /// Handles both POST (with body) and GET (query params only) methods.
+ ///
+ [HttpPost("Sessions/Capabilities")]
+ [HttpPost("Sessions/Capabilities/Full")]
+ [HttpGet("Sessions/Capabilities")]
+ [HttpGet("Sessions/Capabilities/Full")]
+ public async Task ReportCapabilities()
+ {
+ try
+ {
+ var method = Request.Method;
+ var queryString = Request.QueryString.HasValue ? Request.QueryString.Value : "";
+
+ _logger.LogInformation("📡 Session capabilities reported - Method: {Method}, Query: {Query}", method, queryString);
+ _logger.LogInformation("Headers: {Headers}",
+ string.Join(", ", Request.Headers.Where(h => h.Key.Contains("Auth", StringComparison.OrdinalIgnoreCase) || h.Key.Contains("Device", StringComparison.OrdinalIgnoreCase) || h.Key.Contains("Client", StringComparison.OrdinalIgnoreCase))
+ .Select(h => $"{h.Key}={h.Value}")));
+
+ // Forward to Jellyfin with query string and headers
+ var endpoint = $"Sessions/Capabilities{queryString}";
+
+ // Read body if present (POST requests)
+ string body = "{}";
+ if (method == "POST" && Request.ContentLength > 0)
+ {
+ Request.EnableBuffering();
+ using (var reader = new StreamReader(Request.Body, System.Text.Encoding.UTF8, detectEncodingFromByteOrderMarks: false, bufferSize: 1024, leaveOpen: true))
+ {
+ body = await reader.ReadToEndAsync();
+ }
+ Request.Body.Position = 0;
+ _logger.LogInformation("Capabilities body: {Body}", body);
+ }
+
+ var (result, statusCode) = await _proxyService.PostJsonAsync(endpoint, body, Request.Headers);
+
+ if (statusCode == 204 || statusCode == 200)
+ {
+ _logger.LogInformation("✓ Session capabilities forwarded to Jellyfin ({StatusCode})", statusCode);
+ }
+ else
+ {
+ _logger.LogWarning("âš Jellyfin returned {StatusCode} for capabilities", statusCode);
+ }
+
+ return NoContent();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to report session capabilities");
+ return StatusCode(500);
+ }
+ }
+
///
/// Reports playback start. Handles both local and external tracks.
/// For local tracks, forwards to Jellyfin. For external tracks, logs locally.
diff --git a/allstarr/Middleware/WebSocketProxyMiddleware.cs b/allstarr/Middleware/WebSocketProxyMiddleware.cs
index fdcde9c..254b322 100644
--- a/allstarr/Middleware/WebSocketProxyMiddleware.cs
+++ b/allstarr/Middleware/WebSocketProxyMiddleware.cs
@@ -22,10 +22,21 @@ public class WebSocketProxyMiddleware
_next = next;
_settings = settings.Value;
_logger = logger;
+
+ _logger.LogInformation("🔧 WebSocketProxyMiddleware initialized - Jellyfin URL: {Url}", _settings.Url);
}
public async Task InvokeAsync(HttpContext context)
{
+ // Log ALL requests to /socket path for debugging
+ if (context.Request.Path.StartsWithSegments("/socket", StringComparison.OrdinalIgnoreCase))
+ {
+ _logger.LogInformation("📡 Request to /socket path - IsWebSocketRequest: {IsWs}, Method: {Method}, Headers: {Headers}",
+ context.WebSockets.IsWebSocketRequest,
+ context.Request.Method,
+ string.Join(", ", context.Request.Headers.Select(h => $"{h.Key}={h.Value}")));
+ }
+
// Check if this is a WebSocket request to /socket
if (context.Request.Path.StartsWithSegments("/socket", StringComparison.OrdinalIgnoreCase) &&
context.WebSockets.IsWebSocketRequest)