mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 15:45:10 -05:00
fix: include manual external mappings in fallback playlist stats and add live UI refresh
This commit is contained in:
@@ -469,30 +469,53 @@ public class AdminController : ControllerBase
|
||||
foreach (var track in spotifyTracks)
|
||||
{
|
||||
var isLocal = false;
|
||||
var hasExternalMapping = false;
|
||||
|
||||
if (localTracks.Count > 0)
|
||||
// FIRST: Check for manual Jellyfin mapping
|
||||
var manualMappingKey = $"spotify:manual-map:{config.Name}:{track.SpotifyId}";
|
||||
var manualJellyfinId = await _cache.GetAsync<string>(manualMappingKey);
|
||||
|
||||
if (!string.IsNullOrEmpty(manualJellyfinId))
|
||||
{
|
||||
var bestMatch = localTracks
|
||||
.Select(local => new
|
||||
{
|
||||
Local = local,
|
||||
TitleScore = FuzzyMatcher.CalculateSimilarity(track.Title, local.Title),
|
||||
ArtistScore = FuzzyMatcher.CalculateSimilarity(track.PrimaryArtist, local.Artist)
|
||||
})
|
||||
.Select(x => new
|
||||
{
|
||||
x.Local,
|
||||
x.TitleScore,
|
||||
x.ArtistScore,
|
||||
TotalScore = (x.TitleScore * 0.7) + (x.ArtistScore * 0.3)
|
||||
})
|
||||
.OrderByDescending(x => x.TotalScore)
|
||||
.FirstOrDefault();
|
||||
// Manual Jellyfin mapping exists - this track is definitely local
|
||||
isLocal = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for external manual mapping
|
||||
var externalMappingKey = $"spotify:external-map:{config.Name}:{track.SpotifyId}";
|
||||
var externalMappingJson = await _cache.GetStringAsync(externalMappingKey);
|
||||
|
||||
// Use 70% threshold (same as playback matching)
|
||||
if (bestMatch != null && bestMatch.TotalScore >= 70)
|
||||
if (!string.IsNullOrEmpty(externalMappingJson))
|
||||
{
|
||||
isLocal = true;
|
||||
// External manual mapping exists
|
||||
hasExternalMapping = true;
|
||||
}
|
||||
else if (localTracks.Count > 0)
|
||||
{
|
||||
// SECOND: No manual mapping, try fuzzy matching with local tracks
|
||||
var bestMatch = localTracks
|
||||
.Select(local => new
|
||||
{
|
||||
Local = local,
|
||||
TitleScore = FuzzyMatcher.CalculateSimilarity(track.Title, local.Title),
|
||||
ArtistScore = FuzzyMatcher.CalculateSimilarity(track.PrimaryArtist, local.Artist)
|
||||
})
|
||||
.Select(x => new
|
||||
{
|
||||
x.Local,
|
||||
x.TitleScore,
|
||||
x.ArtistScore,
|
||||
TotalScore = (x.TitleScore * 0.7) + (x.ArtistScore * 0.3)
|
||||
})
|
||||
.OrderByDescending(x => x.TotalScore)
|
||||
.FirstOrDefault();
|
||||
|
||||
// Use 70% threshold (same as playback matching)
|
||||
if (bestMatch != null && bestMatch.TotalScore >= 70)
|
||||
{
|
||||
isLocal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,8 +525,8 @@ public class AdminController : ControllerBase
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if external track is matched
|
||||
if (matchedSpotifyIds.Contains(track.SpotifyId))
|
||||
// Check if external track is matched (either manual mapping or auto-matched)
|
||||
if (hasExternalMapping || matchedSpotifyIds.Contains(track.SpotifyId))
|
||||
{
|
||||
externalMatchedCount++;
|
||||
}
|
||||
|
||||
@@ -1202,8 +1202,37 @@
|
||||
if (hash) {
|
||||
switchTab(hash);
|
||||
}
|
||||
|
||||
// Start auto-refresh for playlists tab (every 5 seconds)
|
||||
startPlaylistAutoRefresh();
|
||||
});
|
||||
|
||||
// Auto-refresh functionality for playlists
|
||||
let playlistAutoRefreshInterval = null;
|
||||
|
||||
function startPlaylistAutoRefresh() {
|
||||
// Clear any existing interval
|
||||
if (playlistAutoRefreshInterval) {
|
||||
clearInterval(playlistAutoRefreshInterval);
|
||||
}
|
||||
|
||||
// Refresh every 5 seconds when on playlists tab
|
||||
playlistAutoRefreshInterval = setInterval(() => {
|
||||
const playlistsTab = document.getElementById('tab-playlists');
|
||||
if (playlistsTab && playlistsTab.classList.contains('active')) {
|
||||
// Silently refresh without showing loading state
|
||||
fetchPlaylists(true);
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function stopPlaylistAutoRefresh() {
|
||||
if (playlistAutoRefreshInterval) {
|
||||
clearInterval(playlistAutoRefreshInterval);
|
||||
playlistAutoRefreshInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Toast notification
|
||||
function showToast(message, type = 'success', duration = 3000) {
|
||||
const toast = document.createElement('div');
|
||||
@@ -1343,7 +1372,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchPlaylists() {
|
||||
async function fetchPlaylists(silent = false) {
|
||||
try {
|
||||
const res = await fetch('/api/admin/playlists');
|
||||
const data = await res.json();
|
||||
@@ -1351,7 +1380,9 @@
|
||||
const tbody = document.getElementById('playlist-table-body');
|
||||
|
||||
if (data.playlists.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="7" style="text-align:center;color:var(--text-secondary);padding:40px;">No playlists configured. Link playlists from the Jellyfin Playlists tab.</td></tr>';
|
||||
if (!silent) {
|
||||
tbody.innerHTML = '<tr><td colspan="7" style="text-align:center;color:var(--text-secondary);padding:40px;">No playlists configured. Link playlists from the Jellyfin Playlists tab.</td></tr>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user