perf: stop racing SquidWTF endpoints, use round-robin for parallel processing

Changed from racing all 12 endpoints per track to round-robin distribution. This allows processing 12 tracks in parallel (one per endpoint) instead of wasting requests racing for each track. Also fixed Jellyfin playlist field requests to include all metadata fields.
This commit is contained in:
2026-02-10 12:14:09 -05:00
parent 1d88902e8f
commit c492f085b1
2 changed files with 14 additions and 13 deletions

View File

@@ -992,7 +992,8 @@ public class SpotifyTrackMatchingService : BackgroundService
headers["X-Emby-Authorization"] = $"MediaBrowser Token=\"{jellyfinSettings.ApiKey}\""; headers["X-Emby-Authorization"] = $"MediaBrowser Token=\"{jellyfinSettings.ApiKey}\"";
} }
var playlistItemsUrl = $"Playlists/{jellyfinPlaylistId}/Items?UserId={userId}&Fields=MediaSources"; // Request all fields that clients typically need (not just MediaSources)
var playlistItemsUrl = $"Playlists/{jellyfinPlaylistId}/Items?UserId={userId}&Fields=Genres,DateCreated,MediaSources,ParentId,People,Tags,SortName,ProviderIds";
var (existingTracksResponse, statusCode) = await proxyService.GetJsonAsync(playlistItemsUrl, null, headers); var (existingTracksResponse, statusCode) = await proxyService.GetJsonAsync(playlistItemsUrl, null, headers);
if (statusCode != 200 || existingTracksResponse == null) if (statusCode != 200 || existingTracksResponse == null)

View File

@@ -86,19 +86,19 @@ public class SquidWTFMetadataService : IMusicMetadataService
public async Task<List<Song>> SearchSongsAsync(string query, int limit = 20) public async Task<List<Song>> SearchSongsAsync(string query, int limit = 20)
{ {
// Race all endpoints for fastest search results // Use round-robin to distribute load across endpoints (allows parallel processing of multiple tracks)
return await _fallbackHelper.RaceAllEndpointsAsync(async (baseUrl, ct) => return await _fallbackHelper.TryWithFallbackAsync(async (baseUrl) =>
{ {
// Use 's' parameter for track search as per hifi-api spec // Use 's' parameter for track search as per hifi-api spec
var url = $"{baseUrl}/search/?s={Uri.EscapeDataString(query)}"; var url = $"{baseUrl}/search/?s={Uri.EscapeDataString(query)}";
var response = await _httpClient.GetAsync(url, ct); var response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
throw new HttpRequestException($"HTTP {response.StatusCode}"); throw new HttpRequestException($"HTTP {response.StatusCode}");
} }
var json = await response.Content.ReadAsStringAsync(ct); var json = await response.Content.ReadAsStringAsync();
// Check for error in response body // Check for error in response body
var result = JsonDocument.Parse(json); var result = JsonDocument.Parse(json);
@@ -132,19 +132,19 @@ public class SquidWTFMetadataService : IMusicMetadataService
public async Task<List<Album>> SearchAlbumsAsync(string query, int limit = 20) public async Task<List<Album>> SearchAlbumsAsync(string query, int limit = 20)
{ {
// Race all endpoints for fastest search results // Use round-robin to distribute load across endpoints (allows parallel processing)
return await _fallbackHelper.RaceAllEndpointsAsync(async (baseUrl, ct) => return await _fallbackHelper.TryWithFallbackAsync(async (baseUrl) =>
{ {
// Note: hifi-api doesn't document album search, but 'al' parameter is commonly used // Note: hifi-api doesn't document album search, but 'al' parameter is commonly used
var url = $"{baseUrl}/search/?al={Uri.EscapeDataString(query)}"; var url = $"{baseUrl}/search/?al={Uri.EscapeDataString(query)}";
var response = await _httpClient.GetAsync(url, ct); var response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
throw new HttpRequestException($"HTTP {response.StatusCode}"); throw new HttpRequestException($"HTTP {response.StatusCode}");
} }
var json = await response.Content.ReadAsStringAsync(ct); var json = await response.Content.ReadAsStringAsync();
var result = JsonDocument.Parse(json); var result = JsonDocument.Parse(json);
var albums = new List<Album>(); var albums = new List<Album>();
@@ -169,14 +169,14 @@ public class SquidWTFMetadataService : IMusicMetadataService
public async Task<List<Artist>> SearchArtistsAsync(string query, int limit = 20) public async Task<List<Artist>> SearchArtistsAsync(string query, int limit = 20)
{ {
// Race all endpoints for fastest search results // Use round-robin to distribute load across endpoints (allows parallel processing)
return await _fallbackHelper.RaceAllEndpointsAsync(async (baseUrl, ct) => return await _fallbackHelper.TryWithFallbackAsync(async (baseUrl) =>
{ {
// Per hifi-api spec: use 'a' parameter for artist search // Per hifi-api spec: use 'a' parameter for artist search
var url = $"{baseUrl}/search/?a={Uri.EscapeDataString(query)}"; var url = $"{baseUrl}/search/?a={Uri.EscapeDataString(query)}";
_logger.LogInformation("🔍 SQUIDWTF: Searching artists with URL: {Url}", url); _logger.LogInformation("🔍 SQUIDWTF: Searching artists with URL: {Url}", url);
var response = await _httpClient.GetAsync(url, ct); var response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
@@ -184,7 +184,7 @@ public class SquidWTFMetadataService : IMusicMetadataService
throw new HttpRequestException($"HTTP {response.StatusCode}"); throw new HttpRequestException($"HTTP {response.StatusCode}");
} }
var json = await response.Content.ReadAsStringAsync(ct); var json = await response.Content.ReadAsStringAsync();
var result = JsonDocument.Parse(json); var result = JsonDocument.Parse(json);
var artists = new List<Artist>(); var artists = new List<Artist>();