Show actual local/missing track counts in Active Playlists

- Fetches current Jellyfin playlist track count
- Compares with Spotify playlist total to calculate missing tracks
- Shows: '25 local / 5 missing' instead of just track count
- Local = tracks currently in Jellyfin playlist
- Missing = Spotify tracks not yet in Jellyfin (need to be matched)
- Helps users see which playlists need track matching
This commit is contained in:
2026-02-03 17:48:49 -05:00
parent 363c9e6f1b
commit e51d569d79
2 changed files with 41 additions and 7 deletions

View File

@@ -153,14 +153,19 @@ public class AdminController : ControllerBase
{ {
["name"] = config.Name, ["name"] = config.Name,
["id"] = config.Id, ["id"] = config.Id,
["jellyfinId"] = config.JellyfinId,
["localTracksPosition"] = config.LocalTracksPosition.ToString(), ["localTracksPosition"] = config.LocalTracksPosition.ToString(),
["trackCount"] = 0, ["trackCount"] = 0,
["localTracks"] = 0,
["externalTracks"] = 0,
["lastFetched"] = null as DateTime?, ["lastFetched"] = null as DateTime?,
["cacheAge"] = null as string ["cacheAge"] = null as string
}; };
// Try to get cached playlist data // Get Spotify playlist track count from cache
var cacheFilePath = Path.Combine(CacheDirectory, $"{SanitizeFileName(config.Name)}_spotify.json"); var cacheFilePath = Path.Combine(CacheDirectory, $"{SanitizeFileName(config.Name)}_spotify.json");
int spotifyTrackCount = 0;
if (System.IO.File.Exists(cacheFilePath)) if (System.IO.File.Exists(cacheFilePath))
{ {
try try
@@ -171,7 +176,8 @@ public class AdminController : ControllerBase
if (root.TryGetProperty("tracks", out var tracks)) if (root.TryGetProperty("tracks", out var tracks))
{ {
playlistInfo["trackCount"] = tracks.GetArrayLength(); spotifyTrackCount = tracks.GetArrayLength();
playlistInfo["trackCount"] = spotifyTrackCount;
} }
if (root.TryGetProperty("fetchedAt", out var fetchedAt)) if (root.TryGetProperty("fetchedAt", out var fetchedAt))
@@ -190,6 +196,35 @@ public class AdminController : ControllerBase
} }
} }
// Get current Jellyfin playlist track count
if (!string.IsNullOrEmpty(config.JellyfinId))
{
try
{
var url = $"{_jellyfinSettings.Url}/Playlists/{config.JellyfinId}/Items?Fields=Path";
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add("X-Emby-Authorization", GetJellyfinAuthHeader());
var response = await _jellyfinHttpClient.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var jellyfinJson = await response.Content.ReadAsStringAsync();
using var jellyfinDoc = JsonDocument.Parse(jellyfinJson);
if (jellyfinDoc.RootElement.TryGetProperty("Items", out var items))
{
var localCount = items.GetArrayLength();
playlistInfo["localTracks"] = localCount;
playlistInfo["externalTracks"] = Math.Max(0, spotifyTrackCount - localCount);
}
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to get Jellyfin playlist tracks for {Name}", config.Name);
}
}
playlists.Add(playlistInfo); playlists.Add(playlistInfo);
} }

View File

@@ -1067,11 +1067,10 @@
} }
tbody.innerHTML = data.playlists.map(p => { tbody.innerHTML = data.playlists.map(p => {
// For now, we don't have local/external counts in the API response // Show local tracks and missing tracks
// This will show "-" until we add that data const localCount = p.localTracks || 0;
const localExternal = (p.localTracks !== undefined && p.externalTracks !== undefined) const missingCount = p.externalTracks || 0;
? `${p.localTracks}/${p.externalTracks}` const localExternal = `${localCount} local / ${missingCount} missing`;
: '-';
return ` return `
<tr> <tr>