mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-10 07:58:39 -05:00
fix: intercept existing Jellyfin Spotify playlists
- Check playlist name instead of creating virtual playlists - Intercept playlist items request for Spotify playlists - Fill empty playlists with matched tracks from providers - Works with existing Jellyfin Spotify Import plugin playlists
This commit is contained in:
@@ -220,13 +220,6 @@ public class JellyfinController : ControllerBase
|
||||
mergedAlbums.AddRange(scoredPlaylists);
|
||||
}
|
||||
|
||||
// Inject Spotify playlists if enabled
|
||||
if (_spotifySettings.Enabled)
|
||||
{
|
||||
var spotifyPlaylists = await GetSpotifyPlaylistsAsync(cleanQuery);
|
||||
mergedAlbums.AddRange(spotifyPlaylists);
|
||||
}
|
||||
|
||||
_logger.LogInformation("Scored and filtered results: Songs={Songs}, Albums={Albums}, Artists={Artists}",
|
||||
mergedSongs.Count, mergedAlbums.Count, mergedArtists.Count);
|
||||
|
||||
@@ -1264,17 +1257,50 @@ public class JellyfinController : ControllerBase
|
||||
{
|
||||
try
|
||||
{
|
||||
// Check if this is a Spotify playlist
|
||||
if (playlistId.StartsWith("spotify-"))
|
||||
// Check if this is a Spotify playlist by fetching playlist info first
|
||||
if (_spotifySettings.Enabled && !playlistId.StartsWith("ext-") && !playlistId.StartsWith("playlist-"))
|
||||
{
|
||||
return await GetSpotifyPlaylistTracksAsync(playlistId);
|
||||
// Get playlist info from Jellyfin to check the name
|
||||
var playlistInfo = await _proxyService.GetJsonAsync($"Items/{playlistId}", null, Request.Headers);
|
||||
if (playlistInfo != null && playlistInfo.TryGetProperty("Name", out var nameElement))
|
||||
{
|
||||
var playlistName = nameElement.GetString() ?? "";
|
||||
|
||||
// Check if this matches any configured Spotify playlists
|
||||
var matchingConfig = _spotifySettings.Playlists
|
||||
.FirstOrDefault(p => p.Enabled && p.Name.Equals(playlistName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (matchingConfig != null)
|
||||
{
|
||||
_logger.LogInformation("Intercepting Spotify playlist: {PlaylistName}", playlistName);
|
||||
return await GetSpotifyPlaylistTracksAsync(matchingConfig.SpotifyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this is an external playlist (Deezer/Qobuz)
|
||||
if (PlaylistIdHelper.IsExternalPlaylist(playlistId))
|
||||
{
|
||||
var (provider, externalId) = PlaylistIdHelper.ParsePlaylistId(playlistId);
|
||||
var tracks = await _metadataService.GetPlaylistTracksAsync(provider, externalId);
|
||||
|
||||
return _responseBuilder.CreateItemsResponse(tracks);
|
||||
}
|
||||
|
||||
// Regular Jellyfin playlist - proxy through
|
||||
var endpoint = $"Playlists/{playlistId}/Items";
|
||||
if (Request.QueryString.HasValue)
|
||||
{
|
||||
endpoint = $"{endpoint}{Request.QueryString.Value}";
|
||||
}
|
||||
|
||||
var result = await _proxyService.GetJsonAsync(endpoint, null, Request.Headers);
|
||||
if (result == null)
|
||||
{
|
||||
return _responseBuilder.CreateError(404, "Playlist not found");
|
||||
}
|
||||
|
||||
return new JsonResult(JsonSerializer.Deserialize<object>(result.RootElement.GetRawText()));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error getting playlist tracks {PlaylistId}", playlistId);
|
||||
@@ -1849,55 +1875,19 @@ public class JellyfinController : ControllerBase
|
||||
|
||||
#region Spotify Playlist Injection
|
||||
|
||||
/// <summary>
|
||||
/// Gets Spotify playlists that have cached missing tracks.
|
||||
/// </summary>
|
||||
private async Task<List<Dictionary<string, object?>>> GetSpotifyPlaylistsAsync(string searchQuery)
|
||||
{
|
||||
var playlists = new List<Dictionary<string, object?>>();
|
||||
|
||||
foreach (var playlist in _spotifySettings.Playlists.Where(p => p.Enabled))
|
||||
{
|
||||
var cacheKey = $"spotify:missing:{playlist.SpotifyName}";
|
||||
var hasTracks = await _cache.ExistsAsync(cacheKey);
|
||||
|
||||
if (!hasTracks) continue;
|
||||
|
||||
var score = string.IsNullOrWhiteSpace(searchQuery)
|
||||
? 100
|
||||
: FuzzyMatcher.CalculateSimilarity(searchQuery, playlist.Name);
|
||||
|
||||
if (score < 30 && !string.IsNullOrWhiteSpace(searchQuery)) continue;
|
||||
|
||||
playlists.Add(new Dictionary<string, object?>
|
||||
{
|
||||
["Id"] = $"spotify-{playlist.SpotifyName.ToLower().Replace(" ", "-")}",
|
||||
["Name"] = $"{playlist.Name} - S",
|
||||
["Type"] = "Playlist",
|
||||
["IsFolder"] = false,
|
||||
["MediaType"] = "Audio",
|
||||
["CollectionType"] = "music"
|
||||
});
|
||||
}
|
||||
|
||||
return playlists;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets tracks for a Spotify playlist by matching missing tracks against external providers.
|
||||
/// </summary>
|
||||
private async Task<IActionResult> GetSpotifyPlaylistTracksAsync(string playlistId)
|
||||
private async Task<IActionResult> GetSpotifyPlaylistTracksAsync(string spotifyPlaylistName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var playlistName = playlistId.Replace("spotify-", "").Replace("-", " ");
|
||||
|
||||
var matchingPlaylist = _spotifySettings.Playlists
|
||||
.FirstOrDefault(p => p.SpotifyName.Equals(playlistName, StringComparison.OrdinalIgnoreCase));
|
||||
.FirstOrDefault(p => p.SpotifyName.Equals(spotifyPlaylistName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (matchingPlaylist == null)
|
||||
{
|
||||
_logger.LogWarning("Spotify playlist not found in config: {PlaylistName}", playlistName);
|
||||
_logger.LogWarning("Spotify playlist not found in config: {PlaylistName}", spotifyPlaylistName);
|
||||
return _responseBuilder.CreateItemsResponse(new List<Song>());
|
||||
}
|
||||
|
||||
@@ -1953,7 +1943,7 @@ public class JellyfinController : ControllerBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error getting Spotify playlist tracks {PlaylistId}", playlistId);
|
||||
_logger.LogError(ex, "Error getting Spotify playlist tracks {PlaylistName}", spotifyPlaylistName);
|
||||
return _responseBuilder.CreateError(500, "Failed to get Spotify playlist tracks");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user