Enhanced playlist statistics in admin dashboard

Backend changes:
- Distinguish between local tracks (in Jellyfin library) and external tracks (downloaded)
- Track external matched vs external missing counts
- Calculate completion percentage for each playlist

Frontend changes:
- Show detailed breakdown: X local • Y matched • Z missing
- Display completion percentage with progress bar
- Color-coded stats (green=local, blue=matched, yellow=missing)
- Updated table headers for clarity
This commit is contained in:
2026-02-03 19:49:32 -05:00
parent c1c2212b53
commit af03a53af5
2 changed files with 81 additions and 11 deletions

View File

@@ -243,11 +243,49 @@ public class AdminController : ControllerBase
if (jellyfinDoc.RootElement.TryGetProperty("Items", out var items))
{
var localCount = items.GetArrayLength();
var localCount = 0;
var externalMatchedCount = 0;
// Count local vs external tracks
foreach (var item in items.EnumerateArray())
{
// Check if track has a real file path (local) or is external
var hasPath = item.TryGetProperty("Path", out var pathProp) &&
pathProp.ValueKind == JsonValueKind.String &&
!string.IsNullOrEmpty(pathProp.GetString());
if (hasPath)
{
var pathStr = pathProp.GetString()!;
// Local tracks have filesystem paths starting with / or containing :\
if (pathStr.StartsWith("/") || pathStr.Contains(":\\"))
{
localCount++;
}
else
{
// External track (downloaded from Deezer/Qobuz/etc)
externalMatchedCount++;
}
}
else
{
// No path means external
externalMatchedCount++;
}
}
var totalInJellyfin = localCount + externalMatchedCount;
var externalMissingCount = Math.Max(0, spotifyTrackCount - totalInJellyfin);
playlistInfo["localTracks"] = localCount;
playlistInfo["externalTracks"] = Math.Max(0, spotifyTrackCount - localCount);
_logger.LogDebug("Playlist {Name}: {Local} local tracks, {Missing} missing",
config.Name, localCount, spotifyTrackCount - localCount);
playlistInfo["externalMatched"] = externalMatchedCount;
playlistInfo["externalMissing"] = externalMissingCount;
playlistInfo["externalTotal"] = externalMatchedCount + externalMissingCount;
playlistInfo["totalInJellyfin"] = totalInJellyfin;
_logger.LogDebug("Playlist {Name}: {Total} Spotify tracks, {Local} local, {ExtMatched} external matched, {ExtMissing} external missing",
config.Name, spotifyTrackCount, localCount, externalMatchedCount, externalMissingCount);
}
else
{