mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
Fix playlist count caching and make external tracks perfectly mimic Jellyfin responses
- Fixed UpdateSpotifyPlaylistCounts to properly handle file cache without skipping items - Added Genres and GenreItems fields to all tracks (empty array if no genre) - Added complete MediaStreams with audio codec info for external tracks - Added missing MediaSource fields: IgnoreDts, IgnoreIndex, GenPtsInput, HasSegments - Ensured Artists array never contains null values - All external tracks now have proper genre arrays to match Jellyfin structure
This commit is contained in:
@@ -2780,55 +2780,57 @@ public class JellyfinController : ControllerBase
|
||||
// Use file cache count directly
|
||||
itemDict["ChildCount"] = fileItems.Count;
|
||||
modified = true;
|
||||
updatedItems.Add(itemDict);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Get local tracks count from Jellyfin
|
||||
var localTracksCount = 0;
|
||||
try
|
||||
// Only fetch from Jellyfin if we didn't get count from file cache
|
||||
if (!itemDict.ContainsKey("ChildCount") || (int)itemDict["ChildCount"]! == 0)
|
||||
{
|
||||
var (localTracksResponse, _) = await _proxyService.GetJsonAsync(
|
||||
$"Playlists/{playlistId}/Items",
|
||||
null,
|
||||
Request.Headers);
|
||||
|
||||
if (localTracksResponse != null &&
|
||||
localTracksResponse.RootElement.TryGetProperty("Items", out var localItems))
|
||||
// Get local tracks count from Jellyfin
|
||||
var localTracksCount = 0;
|
||||
try
|
||||
{
|
||||
localTracksCount = localItems.GetArrayLength();
|
||||
_logger.LogInformation("Found {Count} total items in Jellyfin playlist {Name}",
|
||||
localTracksCount, playlistName);
|
||||
var (localTracksResponse, _) = await _proxyService.GetJsonAsync(
|
||||
$"Playlists/{playlistId}/Items",
|
||||
null,
|
||||
Request.Headers);
|
||||
|
||||
if (localTracksResponse != null &&
|
||||
localTracksResponse.RootElement.TryGetProperty("Items", out var localItems))
|
||||
{
|
||||
localTracksCount = localItems.GetArrayLength();
|
||||
_logger.LogInformation("Found {Count} total items in Jellyfin playlist {Name}",
|
||||
localTracksCount, playlistName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to get local tracks count for {Name}", playlistName);
|
||||
}
|
||||
|
||||
// Count external matched tracks (not local)
|
||||
var externalMatchedCount = 0;
|
||||
if (matchedTracks != null)
|
||||
{
|
||||
externalMatchedCount = matchedTracks.Count(t => t.MatchedSong != null && !t.MatchedSong.IsLocal);
|
||||
}
|
||||
|
||||
// Total available tracks = what's actually in Jellyfin (local + external matched)
|
||||
// This is what clients should see as the track count
|
||||
var totalAvailableCount = localTracksCount;
|
||||
|
||||
if (totalAvailableCount > 0)
|
||||
{
|
||||
// Update ChildCount to show actual available tracks
|
||||
itemDict["ChildCount"] = totalAvailableCount;
|
||||
modified = true;
|
||||
_logger.LogInformation("✓ Updated ChildCount for Spotify playlist {Name} to {Total} (actual tracks in Jellyfin)",
|
||||
playlistName, totalAvailableCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("No tracks found in Jellyfin for {Name}", playlistName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to get local tracks count for {Name}", playlistName);
|
||||
}
|
||||
|
||||
// Count external matched tracks (not local)
|
||||
var externalMatchedCount = 0;
|
||||
if (matchedTracks != null)
|
||||
{
|
||||
externalMatchedCount = matchedTracks.Count(t => t.MatchedSong != null && !t.MatchedSong.IsLocal);
|
||||
}
|
||||
|
||||
// Total available tracks = what's actually in Jellyfin (local + external matched)
|
||||
// This is what clients should see as the track count
|
||||
var totalAvailableCount = localTracksCount;
|
||||
|
||||
if (totalAvailableCount > 0)
|
||||
{
|
||||
// Update ChildCount to show actual available tracks
|
||||
itemDict["ChildCount"] = totalAvailableCount;
|
||||
modified = true;
|
||||
_logger.LogInformation("✓ Updated ChildCount for Spotify playlist {Name} to {Total} (actual tracks in Jellyfin)",
|
||||
playlistName, totalAvailableCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("No tracks found in Jellyfin for {Name}", playlistName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ public class JellyfinResponseBuilder
|
||||
["Album"] = song.Album,
|
||||
["AlbumId"] = song.AlbumId ?? song.Id,
|
||||
["AlbumArtist"] = song.AlbumArtist ?? song.Artist,
|
||||
["Artists"] = song.Artists.Count > 0 ? song.Artists.ToArray() : new[] { song.Artist },
|
||||
["Artists"] = song.Artists.Count > 0 ? song.Artists.ToArray() : new[] { song.Artist ?? "" },
|
||||
["ArtistItems"] = song.Artists.Count > 0
|
||||
? song.Artists.Select((name, index) => new Dictionary<string, object?>
|
||||
{
|
||||
@@ -263,7 +263,7 @@ public class JellyfinResponseBuilder
|
||||
new Dictionary<string, object?>
|
||||
{
|
||||
["Id"] = song.ArtistId ?? song.Id,
|
||||
["Name"] = song.Artist
|
||||
["Name"] = song.Artist ?? ""
|
||||
}
|
||||
},
|
||||
["IndexNumber"] = song.Track,
|
||||
@@ -288,7 +288,21 @@ public class JellyfinResponseBuilder
|
||||
["Key"] = $"Audio-{song.Id}"
|
||||
},
|
||||
["CanDownload"] = true,
|
||||
["SupportsSync"] = true
|
||||
["SupportsSync"] = true,
|
||||
// Always include Genres array - use song genre if available, otherwise use a default
|
||||
["Genres"] = !string.IsNullOrEmpty(song.Genre)
|
||||
? new[] { song.Genre }
|
||||
: new string[0], // Empty array instead of null
|
||||
["GenreItems"] = !string.IsNullOrEmpty(song.Genre)
|
||||
? new[]
|
||||
{
|
||||
new Dictionary<string, object?>
|
||||
{
|
||||
["Name"] = song.Genre,
|
||||
["Id"] = $"genre-{song.Genre?.ToLowerInvariant()}"
|
||||
}
|
||||
}
|
||||
: new Dictionary<string, object?>[0]
|
||||
};
|
||||
|
||||
// Add provider IDs for external content
|
||||
@@ -327,15 +341,40 @@ public class JellyfinResponseBuilder
|
||||
["RequiresLooping"] = false,
|
||||
["SupportsProbing"] = true,
|
||||
["ReadAtNativeFramerate"] = false,
|
||||
["MediaStreams"] = new List<object>(), // Empty array instead of null
|
||||
["IgnoreDts"] = false,
|
||||
["IgnoreIndex"] = false,
|
||||
["GenPtsInput"] = false,
|
||||
["MediaStreams"] = new[]
|
||||
{
|
||||
new Dictionary<string, object?>
|
||||
{
|
||||
["Codec"] = "flac",
|
||||
["TimeBase"] = "1/44100",
|
||||
["DisplayTitle"] = "FLAC - Stereo - Default",
|
||||
["IsInterlaced"] = false,
|
||||
["ChannelLayout"] = "stereo",
|
||||
["BitRate"] = 1337000,
|
||||
["Channels"] = 2,
|
||||
["SampleRate"] = 44100,
|
||||
["IsDefault"] = true,
|
||||
["IsForced"] = false,
|
||||
["Type"] = "Audio",
|
||||
["Index"] = 0,
|
||||
["IsExternal"] = false,
|
||||
["IsTextSubtitleStream"] = false,
|
||||
["SupportsExternalStream"] = false,
|
||||
["Level"] = 0
|
||||
}
|
||||
},
|
||||
["MediaAttachments"] = new List<object>(), // Empty array instead of null
|
||||
["Formats"] = new List<object>(), // Empty array instead of null
|
||||
["Formats"] = new List<string>(), // Empty array instead of null
|
||||
["RequiredHttpHeaders"] = new Dictionary<string, string>(), // Empty dict instead of null
|
||||
["RunTimeTicks"] = (song.Duration ?? 180) * 10000000L, // Duration in ticks (100ns units)
|
||||
["Name"] = song.Title,
|
||||
["AnalyzeDurationMs"] = 0,
|
||||
["DefaultAudioStreamIndex"] = 0,
|
||||
["DefaultSubtitleStreamIndex"] = -1
|
||||
["DefaultSubtitleStreamIndex"] = -1,
|
||||
["HasSegments"] = false
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -345,11 +384,6 @@ public class JellyfinResponseBuilder
|
||||
item["MediaSources"] = song.JellyfinMetadata["MediaSources"];
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(song.Genre))
|
||||
{
|
||||
item["Genres"] = new[] { song.Genre };
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user