From c492f085b12831f59439503e843283994a332ebc Mon Sep 17 00:00:00 2001 From: Josh Patra Date: Tue, 10 Feb 2026 12:14:09 -0500 Subject: [PATCH] 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. --- .../Spotify/SpotifyTrackMatchingService.cs | 3 ++- .../SquidWTF/SquidWTFMetadataService.cs | 24 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/allstarr/Services/Spotify/SpotifyTrackMatchingService.cs b/allstarr/Services/Spotify/SpotifyTrackMatchingService.cs index bd45db5..31c3245 100644 --- a/allstarr/Services/Spotify/SpotifyTrackMatchingService.cs +++ b/allstarr/Services/Spotify/SpotifyTrackMatchingService.cs @@ -992,7 +992,8 @@ public class SpotifyTrackMatchingService : BackgroundService 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); if (statusCode != 200 || existingTracksResponse == null) diff --git a/allstarr/Services/SquidWTF/SquidWTFMetadataService.cs b/allstarr/Services/SquidWTF/SquidWTFMetadataService.cs index 4198929..22531bb 100644 --- a/allstarr/Services/SquidWTF/SquidWTFMetadataService.cs +++ b/allstarr/Services/SquidWTF/SquidWTFMetadataService.cs @@ -86,19 +86,19 @@ public class SquidWTFMetadataService : IMusicMetadataService public async Task> SearchSongsAsync(string query, int limit = 20) { - // Race all endpoints for fastest search results - return await _fallbackHelper.RaceAllEndpointsAsync(async (baseUrl, ct) => + // Use round-robin to distribute load across endpoints (allows parallel processing of multiple tracks) + return await _fallbackHelper.TryWithFallbackAsync(async (baseUrl) => { // Use 's' parameter for track search as per hifi-api spec var url = $"{baseUrl}/search/?s={Uri.EscapeDataString(query)}"; - var response = await _httpClient.GetAsync(url, ct); + var response = await _httpClient.GetAsync(url); if (!response.IsSuccessStatusCode) { 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 var result = JsonDocument.Parse(json); @@ -132,19 +132,19 @@ public class SquidWTFMetadataService : IMusicMetadataService public async Task> SearchAlbumsAsync(string query, int limit = 20) { - // Race all endpoints for fastest search results - return await _fallbackHelper.RaceAllEndpointsAsync(async (baseUrl, ct) => + // Use round-robin to distribute load across endpoints (allows parallel processing) + return await _fallbackHelper.TryWithFallbackAsync(async (baseUrl) => { // Note: hifi-api doesn't document album search, but 'al' parameter is commonly used var url = $"{baseUrl}/search/?al={Uri.EscapeDataString(query)}"; - var response = await _httpClient.GetAsync(url, ct); + var response = await _httpClient.GetAsync(url); if (!response.IsSuccessStatusCode) { 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 albums = new List(); @@ -169,14 +169,14 @@ public class SquidWTFMetadataService : IMusicMetadataService public async Task> SearchArtistsAsync(string query, int limit = 20) { - // Race all endpoints for fastest search results - return await _fallbackHelper.RaceAllEndpointsAsync(async (baseUrl, ct) => + // Use round-robin to distribute load across endpoints (allows parallel processing) + return await _fallbackHelper.TryWithFallbackAsync(async (baseUrl) => { // Per hifi-api spec: use 'a' parameter for artist search var url = $"{baseUrl}/search/?a={Uri.EscapeDataString(query)}"; _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) { @@ -184,7 +184,7 @@ public class SquidWTFMetadataService : IMusicMetadataService 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 artists = new List();