fix(jellyfin): preserve routed provider identities

This commit is contained in:
joshpatra committed 2026-08-05 19:55:09 -04:00
1 parent 3969ead693
commit 119b8d7ef4
4 files changed
+22 -7

No files matched your search

@@ -2381,6 +2381,7 @@ public sealed class ProtocolRouteFixtureTests
var actual = JsonNode.Parse(
tracks.RootElement.GetProperty("Items")[0].GetRawText())!.AsObject();
var expected = JsonNode.Parse(originalItem)!.AsObject();
expected["ProviderIds"]!["AllstarrSource"] = "spotify";
expected["ParentId"] = virtualId;
expected["PlaylistItemId"] = "local-song-a";
@@ -2389,7 +2390,7 @@ public sealed class ProtocolRouteFixtureTests
$"Expected full source DTO with playlist overlays.\nExpected: {expected}\nActual: {actual}");
Assert.Equal("Original Track", actual["Name"]!.GetValue<string>());
Assert.Equal(virtualId, actual["ParentId"]!.GetValue<string>());
Assert.False(actual["ProviderIds"]!.AsObject().ContainsKey("AllstarrSource"));
Assert.Equal("spotify", actual["ProviderIds"]!["AllstarrSource"]!.GetValue<string>());
Assert.Equal("local-song-a", actual["Id"]!.GetValue<string>());
Assert.Equal("local-song-a", actual["PlaylistItemId"]!.GetValue<string>());
Assert.Equal("album-original", actual["AlbumId"]!.GetValue<string>());
@@ -253,7 +253,7 @@ public sealed class DeezerMetadataCapabilityAdapterTests
]);
legacy.Setup(item => item.GetArtistTracksAsync("deezer", "artist-1", It.IsAny<CancellationToken>()))
.ReturnsAsync([
new Song { ExternalId = "track-1", Title = "First", Artist = "Artist", Artists = ["Artist"] },
new Song { ExternalId = "track-1", Title = "First", Artist = "Artist", Artists = ["Artist"], ArtistId = "artist-1" },
new Song { ExternalId = "track-2", Title = "Second", Artist = "Artist", Artists = ["Artist"] }
]);
var adapter = new DeezerMetadataCapabilityAdapter(legacy.Object);
@@ -272,6 +272,7 @@ public sealed class DeezerMetadataCapabilityAdapterTests
Assert.Equal("album-3", Assert.Single(remaining.Items).Id.Value);
Assert.Null(remaining.NextCursor);
Assert.Equal(["track-1", "track-2"], tracks.Items.Select(item => item.Id.Value));
Assert.Equal("artist-1", tracks.Items[0].Artists[0].ArtistId!.Value);
legacy.VerifyAll();
}
@@ -314,6 +314,13 @@ public sealed class JellyfinVirtualPlaylistProtocolAdapter(
}
}
if (track.RouteKind == TrackRouteKind.Local &&
!string.IsNullOrWhiteSpace(track.SourceProviderId))
{
var providerIds = item["ProviderIds"] as JsonObject ?? [];
item["ProviderIds"] = providerIds;
providerIds["AllstarrSource"] = track.SourceProviderId;
}
item["ParentId"] = responsePlaylistId;
item["PlaylistItemId"] = track.NativePlaylistEntryId ?? track.BackendItemId;
return item;
@@ -210,11 +210,17 @@ public abstract class ConcreteMetadataCapabilityAdapter(
if (names.Length == 0)
throw new InvalidOperationException($"The {ProviderId} track has no artist credit.");
var credits = names.Select((name, index) => new ProviderArtistCredit(
name.Trim(),
index < song.ArtistIds.Count && !string.IsNullOrWhiteSpace(song.ArtistIds[index])
? ExternalId(ProviderResourceKind.Artist, song.ArtistIds[index], null, "artist")
: null));
var credits = names.Select((name, index) =>
{
var artistId = index < song.ArtistIds.Count && !string.IsNullOrWhiteSpace(song.ArtistIds[index])
? song.ArtistIds[index]
: index == 0 ? song.ArtistId : null;
return new ProviderArtistCredit(
name.Trim(),
string.IsNullOrWhiteSpace(artistId)
? null
: ExternalId(ProviderResourceKind.Artist, artistId, null, "artist"));
});
var albumId = string.IsNullOrWhiteSpace(song.AlbumId)
? null
: ExternalId(ProviderResourceKind.Album, song.AlbumId, null, "album");