From 72b1ebc2eb3a9c4e9054a6c87e975182034ec399 Mon Sep 17 00:00:00 2001 From: Josh Patra Date: Fri, 30 Jan 2026 00:48:38 -0500 Subject: [PATCH] Fix: Wrap playback request bodies in required field names for Jellyfin Jellyfin expects playback endpoints to have bodies wrapped: - /Sessions/Playing -> {"playbackStartInfo": {...}} - /Sessions/Playing/Progress -> {"playbackProgressInfo": {...}} - /Sessions/Playing/Stopped -> {"playbackStopInfo": {...}} This fixes the 'field is required' validation errors. --- .../Services/Jellyfin/JellyfinProxyService.cs | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/allstarr/Services/Jellyfin/JellyfinProxyService.cs b/allstarr/Services/Jellyfin/JellyfinProxyService.cs index d866103..4cbeba3 100644 --- a/allstarr/Services/Jellyfin/JellyfinProxyService.cs +++ b/allstarr/Services/Jellyfin/JellyfinProxyService.cs @@ -256,16 +256,40 @@ public class JellyfinProxyService using var request = new HttpRequestMessage(HttpMethod.Post, url); - // Create content from body string - ALWAYS set content even if empty - // Jellyfin expects a body for POST requests, even if it's "{}" - var bodyToSend = string.IsNullOrWhiteSpace(body) ? "{}" : body; - request.Content = new StringContent(bodyToSend, System.Text.Encoding.UTF8, "application/json"); - - if (string.IsNullOrWhiteSpace(body)) + // Handle special case for playback endpoints - Jellyfin expects wrapped body + var bodyToSend = body; + if (!string.IsNullOrWhiteSpace(body)) { + // Check if this is a playback progress endpoint + if (endpoint.Contains("Sessions/Playing/Progress", StringComparison.OrdinalIgnoreCase)) + { + // Wrap the body in playbackProgressInfo field + bodyToSend = $"{{\"playbackProgressInfo\":{body}}}"; + _logger.LogDebug("Wrapped body for playback progress endpoint"); + } + else if (endpoint.Contains("Sessions/Playing/Stopped", StringComparison.OrdinalIgnoreCase)) + { + // Wrap the body in playbackStopInfo field + bodyToSend = $"{{\"playbackStopInfo\":{body}}}"; + _logger.LogDebug("Wrapped body for playback stopped endpoint"); + } + else if (endpoint.Contains("Sessions/Playing", StringComparison.OrdinalIgnoreCase) && + !endpoint.Contains("Progress", StringComparison.OrdinalIgnoreCase) && + !endpoint.Contains("Stopped", StringComparison.OrdinalIgnoreCase)) + { + // Wrap the body in playbackStartInfo field for /Sessions/Playing + bodyToSend = $"{{\"playbackStartInfo\":{body}}}"; + _logger.LogDebug("Wrapped body for playback start endpoint"); + } + } + else + { + bodyToSend = "{}"; _logger.LogWarning("POST body was empty for {Url}, sending empty JSON object", url); } + request.Content = new StringContent(bodyToSend, System.Text.Encoding.UTF8, "application/json"); + bool authHeaderAdded = false; // Forward authentication headers from client (case-insensitive)