mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
Fix Spotify playlist injection: add dedicated route, startup fetch, and clarify config
This commit is contained in:
@@ -98,9 +98,9 @@ CACHE_DURATION_HOURS=1
|
|||||||
|
|
||||||
# ===== SPOTIFY PLAYLIST INJECTION (JELLYFIN ONLY) =====
|
# ===== SPOTIFY PLAYLIST INJECTION (JELLYFIN ONLY) =====
|
||||||
# REQUIRES: Jellyfin Spotify Import Plugin (https://github.com/Viperinius/jellyfin-plugin-spotify-import)
|
# REQUIRES: Jellyfin Spotify Import Plugin (https://github.com/Viperinius/jellyfin-plugin-spotify-import)
|
||||||
# This feature injects virtual Spotify playlists (Release Radar, Discover Weekly) into Jellyfin
|
# This feature intercepts Spotify Import plugin playlists (Release Radar, Discover Weekly) and fills them
|
||||||
# with tracks auto-matched from external providers (SquidWTF, Deezer, Qobuz)
|
# with tracks auto-matched from external providers (SquidWTF, Deezer, Qobuz)
|
||||||
# Uses JELLYFIN_URL and JELLYFIN_API_KEY for API access
|
# Uses JELLYFIN_URL and JELLYFIN_API_KEY configured above (no separate credentials needed)
|
||||||
|
|
||||||
# Enable Spotify playlist injection (optional, default: false)
|
# Enable Spotify playlist injection (optional, default: false)
|
||||||
SPOTIFY_IMPORT_ENABLED=false
|
SPOTIFY_IMPORT_ENABLED=false
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -90,7 +90,7 @@ This project brings together all the music streaming providers into one unified
|
|||||||
- **Artist Deduplication**: Merges local and streaming artists to avoid duplicates
|
- **Artist Deduplication**: Merges local and streaming artists to avoid duplicates
|
||||||
- **Album Enrichment**: Adds missing tracks to local albums from streaming providers
|
- **Album Enrichment**: Adds missing tracks to local albums from streaming providers
|
||||||
- **Cover Art Proxy**: Serves cover art for external content
|
- **Cover Art Proxy**: Serves cover art for external content
|
||||||
- **Spotify Playlist Injection** (Jellyfin only): Injects virtual Spotify playlists (Release Radar, Discover Weekly) with tracks auto-matched from streaming providers
|
- **Spotify Playlist Injection** (Jellyfin only): Intercepts Spotify Import plugin playlists (Release Radar, Discover Weekly) and fills them with tracks auto-matched from streaming providers
|
||||||
|
|
||||||
## Supported Backends
|
## Supported Backends
|
||||||
|
|
||||||
@@ -290,7 +290,7 @@ Subsonic__EnableExternalPlaylists=false
|
|||||||
|
|
||||||
### Spotify Playlist Injection (Jellyfin Only)
|
### Spotify Playlist Injection (Jellyfin Only)
|
||||||
|
|
||||||
Allstarr can inject virtual Spotify playlists (Release Radar, Discover Weekly) into Jellyfin with tracks automatically matched from your configured streaming provider.
|
Allstarr can intercept Spotify Import plugin playlists (Release Radar, Discover Weekly) and fill them with tracks automatically matched from your configured streaming provider (SquidWTF, Deezer, or Qobuz).
|
||||||
|
|
||||||
**Requirements:**
|
**Requirements:**
|
||||||
- [Jellyfin Spotify Import Plugin](https://github.com/Viperinius/jellyfin-plugin-spotify-import) installed and configured
|
- [Jellyfin Spotify Import Plugin](https://github.com/Viperinius/jellyfin-plugin-spotify-import) installed and configured
|
||||||
@@ -308,11 +308,12 @@ Allstarr can inject virtual Spotify playlists (Release Radar, Discover Weekly) i
|
|||||||
| `SpotifyImport:Playlists` | Array of playlists to inject (Name, SpotifyName, Enabled) |
|
| `SpotifyImport:Playlists` | Array of playlists to inject (Name, SpotifyName, Enabled) |
|
||||||
|
|
||||||
**How it works:**
|
**How it works:**
|
||||||
1. Jellyfin Spotify Import plugin runs daily and creates missing tracks files for playlists
|
1. Jellyfin Spotify Import plugin runs daily and creates playlists + missing tracks files
|
||||||
2. Allstarr fetches these files within the configured time window
|
2. Allstarr fetches these missing tracks files within the configured time window
|
||||||
3. For each missing track, Allstarr searches your streaming provider (SquidWTF, Deezer, or Qobuz)
|
3. For each missing track, Allstarr searches your streaming provider (SquidWTF, Deezer, or Qobuz)
|
||||||
4. Virtual playlists appear in Jellyfin with matched tracks ready to stream
|
4. When you open the playlist in Jellyfin, Allstarr intercepts the request and returns matched tracks
|
||||||
5. Tracks are downloaded on-demand when played
|
5. Tracks are downloaded on-demand when played
|
||||||
|
6. On startup, Allstarr will fetch missing tracks if it hasn't run in the last 24 hours
|
||||||
|
|
||||||
**Environment variables:**
|
**Environment variables:**
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -1210,6 +1210,17 @@ public class JellyfinController : ControllerBase
|
|||||||
|
|
||||||
#region Playlists
|
#region Playlists
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Intercepts playlist items requests to inject Spotify playlists.
|
||||||
|
/// This route must have lower Order than the catch-all ProxyRequest route.
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("Playlists/{playlistId}/Items", Order = 5)]
|
||||||
|
public async Task<IActionResult> GetPlaylistItems(string playlistId)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("GetPlaylistItems called for playlist {PlaylistId}", playlistId);
|
||||||
|
return await GetPlaylistTracks(playlistId);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets playlist tracks displayed as an album.
|
/// Gets playlist tracks displayed as an album.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public class SpotifyMissingTracksFetcher : BackgroundService
|
|||||||
private readonly IHttpClientFactory _httpClientFactory;
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
private readonly RedisCacheService _cache;
|
private readonly RedisCacheService _cache;
|
||||||
private readonly ILogger<SpotifyMissingTracksFetcher> _logger;
|
private readonly ILogger<SpotifyMissingTracksFetcher> _logger;
|
||||||
|
private bool _hasRunOnce = false;
|
||||||
|
|
||||||
public SpotifyMissingTracksFetcher(
|
public SpotifyMissingTracksFetcher(
|
||||||
IOptions<SpotifyImportSettings> spotifySettings,
|
IOptions<SpotifyImportSettings> spotifySettings,
|
||||||
@@ -47,6 +48,30 @@ public class SpotifyMissingTracksFetcher : BackgroundService
|
|||||||
|
|
||||||
_logger.LogInformation("Spotify missing tracks fetcher started");
|
_logger.LogInformation("Spotify missing tracks fetcher started");
|
||||||
|
|
||||||
|
// Run once on startup if we haven't run in the last 24 hours
|
||||||
|
if (!_hasRunOnce)
|
||||||
|
{
|
||||||
|
var shouldRunOnStartup = await ShouldRunOnStartupAsync();
|
||||||
|
if (shouldRunOnStartup)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Running initial fetch on startup");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await FetchMissingTracksAsync(stoppingToken);
|
||||||
|
_hasRunOnce = true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error during startup fetch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Skipping startup fetch - already ran within last 24 hours");
|
||||||
|
_hasRunOnce = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -62,6 +87,20 @@ public class SpotifyMissingTracksFetcher : BackgroundService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<bool> ShouldRunOnStartupAsync()
|
||||||
|
{
|
||||||
|
// Check if any playlist has cached data from the last 24 hours
|
||||||
|
foreach (var playlist in _spotifySettings.Value.Playlists.Where(p => p.Enabled))
|
||||||
|
{
|
||||||
|
var cacheKey = $"spotify:missing:{playlist.SpotifyName}";
|
||||||
|
if (await _cache.ExistsAsync(cacheKey))
|
||||||
|
{
|
||||||
|
return false; // Already have recent data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true; // No recent data, should fetch
|
||||||
|
}
|
||||||
|
|
||||||
private async Task FetchMissingTracksAsync(CancellationToken cancellationToken)
|
private async Task FetchMissingTracksAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var settings = _spotifySettings.Value;
|
var settings = _spotifySettings.Value;
|
||||||
|
|||||||
Reference in New Issue
Block a user