fix(jellyfin): preserve native playlist totals

This commit is contained in:
joshpatra committed 2026-08-15 15:47:34 -04:00
1 parent 58c9e285d8
commit 2428223fed
2 files changed
+34 -2

No files matched your search

@@ -557,6 +557,31 @@ public sealed class ProtocolRouteFixtureTests
Assert.Equal(HttpMethod.Head, observedMethod);
}
[Fact]
public async Task JellyfinNativePlaylistItems_PreserveUpstreamTotalWhenEveryRowIsAudio()
{
const string playlistId = "0123456789abcdef0123456789abcdef";
using var factory = new ProtocolFactory("Jellyfin", request =>
{
if (request.RequestUri!.AbsolutePath == "/Users/Me")
return Json(StatusCodes.Status200OK, """{"Id":"user-1","Name":"Fixture User"}""");
if (request.RequestUri.AbsolutePath == "/Items")
return ItemLookup($$"""{"Id":"{{playlistId}}","Type":"Playlist"}""");
return Json(StatusCodes.Status200OK,
"""{"Items":[{"Id":"song-1","Type":"Audio","Sentinel":"complete"}],"TotalRecordCount":903,"StartIndex":0}""");
});
using var client = factory.CreateClient();
using var response = await client.GetAsync(
$"/Playlists/{playlistId}/Items?Limit=100&api_key=fixture-key");
using var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(903, body.RootElement.GetProperty("TotalRecordCount").GetInt32());
Assert.Equal("complete",
body.RootElement.GetProperty("Items")[0].GetProperty("Sentinel").GetString());
}
[Fact]
public async Task JellyfinSearchAdapter_PreservesFixtureStatusBodyAndPaging()
{
@@ -74,7 +74,13 @@ public partial class JellyfinController
});
}
var endpoint = $"Items/{Uri.EscapeDataString(musicLibraryId)}{Request.QueryString.Value}";
var credentialQuery = Request.Query
.Where(item => item.Key.Equals("api_key", StringComparison.OrdinalIgnoreCase) ||
item.Key.Equals("access_token", StringComparison.OrdinalIgnoreCase) ||
item.Key.Equals("ApiKey", StringComparison.OrdinalIgnoreCase))
.SelectMany(item => item.Value.Select(value =>
new KeyValuePair<string, string?>(item.Key, value)));
var endpoint = $"Items/{Uri.EscapeDataString(musicLibraryId)}{QueryString.Create(credentialQuery)}";
var (body, statusCode) = await _proxyService.GetJsonAsync(endpoint, null, Request.Headers);
return HandleProxyResponse(body, statusCode);
}
@@ -198,6 +204,7 @@ public partial class JellyfinController
};
}
var originalCount = items.Count;
var filtered = items
.Where(item => item is JsonObject candidate &&
JellyfinMusicEndpointPolicy.IsMusicItemType(candidate["Type"]?.GetValue<string>()))
@@ -205,7 +212,7 @@ public partial class JellyfinController
.ToArray();
items.Clear();
foreach (var item in filtered) items.Add(item);
root["TotalRecordCount"] = filtered.Length;
if (filtered.Length != originalCount) root["TotalRecordCount"] = filtered.Length;
return new ContentResult
{
Content = root.ToJsonString(),