mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
websocket fix
This commit is contained in:
@@ -1731,6 +1731,7 @@ public class JellyfinController : ControllerBase
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reports playback start. Handles both local and external tracks.
|
/// Reports playback start. Handles both local and external tracks.
|
||||||
/// For local tracks, forwards to Jellyfin. For external tracks, logs locally.
|
/// For local tracks, forwards to Jellyfin. For external tracks, logs locally.
|
||||||
|
/// Also ensures session is initialized if this is the first report from a device.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpPost("Sessions/Playing")]
|
[HttpPost("Sessions/Playing")]
|
||||||
public async Task<IActionResult> ReportPlaybackStart()
|
public async Task<IActionResult> ReportPlaybackStart()
|
||||||
@@ -1749,6 +1750,50 @@ public class JellyfinController : ControllerBase
|
|||||||
_logger.LogInformation("Auth headers: {Headers}",
|
_logger.LogInformation("Auth headers: {Headers}",
|
||||||
string.Join(", ", Request.Headers.Where(h => h.Key.Contains("Auth", StringComparison.OrdinalIgnoreCase)).Select(h => $"{h.Key}={h.Value}")));
|
string.Join(", ", Request.Headers.Where(h => h.Key.Contains("Auth", StringComparison.OrdinalIgnoreCase)).Select(h => $"{h.Key}={h.Value}")));
|
||||||
|
|
||||||
|
// Extract device info from auth headers for session initialization
|
||||||
|
string? deviceId = null;
|
||||||
|
string? client = null;
|
||||||
|
string? device = null;
|
||||||
|
string? version = null;
|
||||||
|
|
||||||
|
if (Request.Headers.TryGetValue("Authorization", out var authHeader))
|
||||||
|
{
|
||||||
|
var authStr = authHeader.ToString();
|
||||||
|
// Parse: MediaBrowser Client="...", Device="...", DeviceId="...", Version="..."
|
||||||
|
var parts = authStr.Replace("MediaBrowser ", "").Split(',');
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
var kv = part.Trim().Split('=');
|
||||||
|
if (kv.Length == 2)
|
||||||
|
{
|
||||||
|
var key = kv[0].Trim();
|
||||||
|
var value = kv[1].Trim('"');
|
||||||
|
if (key == "DeviceId") deviceId = value;
|
||||||
|
else if (key == "Client") client = value;
|
||||||
|
else if (key == "Device") device = value;
|
||||||
|
else if (key == "Version") version = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure session capabilities are posted to Jellyfin (if not already done)
|
||||||
|
if (!string.IsNullOrEmpty(deviceId))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("🔧 Ensuring session exists for device: {DeviceId} ({Client} {Version})", deviceId, client, version);
|
||||||
|
|
||||||
|
// Post capabilities to ensure session is created
|
||||||
|
var capabilitiesEndpoint = $"Sessions/Capabilities?playableMediaTypes=Audio&supportedCommands=&supportsMediaControl=false&supportsPersistentIdentifier=true";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var (capResult, capStatus) = await _proxyService.PostJsonAsync(capabilitiesEndpoint, "{}", Request.Headers);
|
||||||
|
_logger.LogInformation("✓ Session capabilities posted ({StatusCode})", capStatus);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Failed to post session capabilities, continuing anyway");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the body to check if it's an external track
|
// Parse the body to check if it's an external track
|
||||||
var doc = JsonDocument.Parse(body);
|
var doc = JsonDocument.Parse(body);
|
||||||
string? itemId = null;
|
string? itemId = null;
|
||||||
@@ -1945,6 +1990,60 @@ public class JellyfinController : ControllerBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Catch-all for any other session-related requests.
|
||||||
|
/// This ensures all session management calls get proxied to Jellyfin.
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("Sessions/{**path}")]
|
||||||
|
[HttpPost("Sessions/{**path}")]
|
||||||
|
[HttpPut("Sessions/{**path}")]
|
||||||
|
[HttpDelete("Sessions/{**path}")]
|
||||||
|
public async Task<IActionResult> ProxySessionRequest(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var method = Request.Method;
|
||||||
|
var queryString = Request.QueryString.HasValue ? Request.QueryString.Value : "";
|
||||||
|
var endpoint = $"Sessions/{path}{queryString}";
|
||||||
|
|
||||||
|
_logger.LogInformation("🔄 Proxying session request: {Method} {Endpoint}", method, endpoint);
|
||||||
|
|
||||||
|
// Read body if present
|
||||||
|
string body = "{}";
|
||||||
|
if ((method == "POST" || method == "PUT") && 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward to Jellyfin
|
||||||
|
var (result, statusCode) = method switch
|
||||||
|
{
|
||||||
|
"GET" => await _proxyService.GetJsonAsync(endpoint, null, Request.Headers),
|
||||||
|
"POST" => await _proxyService.PostJsonAsync(endpoint, body, Request.Headers),
|
||||||
|
"PUT" => await _proxyService.PostJsonAsync(endpoint, body, Request.Headers), // Use POST for PUT
|
||||||
|
"DELETE" => await _proxyService.PostJsonAsync(endpoint, body, Request.Headers), // Use POST for DELETE
|
||||||
|
_ => (null, 405)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return new JsonResult(result.RootElement.Clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
return StatusCode(statusCode);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Failed to proxy session request");
|
||||||
|
return StatusCode(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion // Session Management
|
#endregion // Session Management
|
||||||
|
|
||||||
#endregion // Playback Session Reporting
|
#endregion // Playback Session Reporting
|
||||||
@@ -1989,8 +2088,16 @@ public class JellyfinController : ControllerBase
|
|||||||
[HttpPost("{**path}", Order = 100)]
|
[HttpPost("{**path}", Order = 100)]
|
||||||
public async Task<IActionResult> ProxyRequest(string path)
|
public async Task<IActionResult> ProxyRequest(string path)
|
||||||
{
|
{
|
||||||
// DEBUG: Log EVERY request to see what's happening
|
// Log session-related requests prominently to debug missing capabilities call
|
||||||
_logger.LogWarning("ProxyRequest called with path: {Path}", path);
|
if (path.Contains("session", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
path.Contains("capabilit", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("🔍 SESSION/CAPABILITY REQUEST: {Method} /{Path}{Query}", Request.Method, path, Request.QueryString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogDebug("ProxyRequest: {Method} /{Path}", Request.Method, path);
|
||||||
|
}
|
||||||
|
|
||||||
// Log endpoint usage to file for analysis
|
// Log endpoint usage to file for analysis
|
||||||
await LogEndpointUsageAsync(path, Request.Method);
|
await LogEndpointUsageAsync(path, Request.Method);
|
||||||
@@ -2216,7 +2323,8 @@ public class JellyfinController : ControllerBase
|
|||||||
result = await UpdateSpotifyPlaylistCounts(result);
|
result = await UpdateSpotifyPlaylistCounts(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JsonResult(JsonSerializer.Deserialize<object>(result.RootElement.GetRawText()));
|
// Return the raw JSON element directly to avoid deserialization issues with simple types
|
||||||
|
return new JsonResult(result.RootElement.Clone());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user