mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
Fix SpotifyMissingTracksFetcher to work with ID-based configuration and add detailed logging
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
using allstarr.Models.Settings;
|
using allstarr.Models.Settings;
|
||||||
using allstarr.Models.Spotify;
|
using allstarr.Models.Spotify;
|
||||||
using allstarr.Services.Common;
|
using allstarr.Services.Common;
|
||||||
|
using allstarr.Services.Jellyfin;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
@@ -13,31 +14,35 @@ 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 readonly JellyfinProxyService _proxyService;
|
||||||
private bool _hasRunOnce = false;
|
private bool _hasRunOnce = false;
|
||||||
|
private Dictionary<string, string> _playlistIdToName = new();
|
||||||
|
|
||||||
public SpotifyMissingTracksFetcher(
|
public SpotifyMissingTracksFetcher(
|
||||||
IOptions<SpotifyImportSettings> spotifySettings,
|
IOptions<SpotifyImportSettings> spotifySettings,
|
||||||
IOptions<JellyfinSettings> jellyfinSettings,
|
IOptions<JellyfinSettings> jellyfinSettings,
|
||||||
IHttpClientFactory httpClientFactory,
|
IHttpClientFactory httpClientFactory,
|
||||||
RedisCacheService cache,
|
RedisCacheService cache,
|
||||||
|
JellyfinProxyService proxyService,
|
||||||
ILogger<SpotifyMissingTracksFetcher> logger)
|
ILogger<SpotifyMissingTracksFetcher> logger)
|
||||||
{
|
{
|
||||||
_spotifySettings = spotifySettings;
|
_spotifySettings = spotifySettings;
|
||||||
_jellyfinSettings = jellyfinSettings;
|
_jellyfinSettings = jellyfinSettings;
|
||||||
_httpClientFactory = httpClientFactory;
|
_httpClientFactory = httpClientFactory;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
|
_proxyService = proxyService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_logger.LogInformation("SpotifyMissingTracksFetcher: Constructor called");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("========================================");
|
||||||
_logger.LogInformation("SpotifyMissingTracksFetcher: Starting up...");
|
_logger.LogInformation("SpotifyMissingTracksFetcher: Starting up...");
|
||||||
|
|
||||||
if (!_spotifySettings.Value.Enabled)
|
if (!_spotifySettings.Value.Enabled)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Spotify playlist injection is disabled");
|
_logger.LogInformation("Spotify playlist injection is DISABLED");
|
||||||
|
_logger.LogInformation("========================================");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,17 +52,21 @@ public class SpotifyMissingTracksFetcher : BackgroundService
|
|||||||
if (string.IsNullOrEmpty(jellyfinUrl) || string.IsNullOrEmpty(apiKey))
|
if (string.IsNullOrEmpty(jellyfinUrl) || string.IsNullOrEmpty(apiKey))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Jellyfin URL or API key not configured, Spotify playlist injection disabled");
|
_logger.LogWarning("Jellyfin URL or API key not configured, Spotify playlist injection disabled");
|
||||||
|
_logger.LogInformation("========================================");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Spotify missing tracks fetcher started - monitoring {Count} playlists",
|
_logger.LogInformation("Spotify Import ENABLED");
|
||||||
_spotifySettings.Value.Playlists.Count);
|
_logger.LogInformation("Configured Playlist IDs: {Count}", _spotifySettings.Value.PlaylistIds.Count);
|
||||||
|
|
||||||
foreach (var playlist in _spotifySettings.Value.Playlists)
|
// Fetch playlist names from Jellyfin
|
||||||
|
await LoadPlaylistNamesAsync();
|
||||||
|
|
||||||
|
foreach (var kvp in _playlistIdToName)
|
||||||
{
|
{
|
||||||
_logger.LogInformation(" - {Name} (SpotifyName: {SpotifyName}, Enabled: {Enabled})",
|
_logger.LogInformation(" - {Name} (ID: {Id})", kvp.Value, kvp.Key);
|
||||||
playlist.Name, playlist.SpotifyName, playlist.Enabled);
|
|
||||||
}
|
}
|
||||||
|
_logger.LogInformation("========================================");
|
||||||
|
|
||||||
// Run once on startup if we haven't run in the last 24 hours
|
// Run once on startup if we haven't run in the last 24 hours
|
||||||
if (!_hasRunOnce)
|
if (!_hasRunOnce)
|
||||||
@@ -98,12 +107,37 @@ public class SpotifyMissingTracksFetcher : BackgroundService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task LoadPlaylistNamesAsync()
|
||||||
|
{
|
||||||
|
_playlistIdToName.Clear();
|
||||||
|
|
||||||
|
foreach (var playlistId in _spotifySettings.Value.PlaylistIds)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var playlistInfo = await _proxyService.GetJsonAsync($"Items/{playlistId}", null, null);
|
||||||
|
if (playlistInfo != null && playlistInfo.RootElement.TryGetProperty("Name", out var nameElement))
|
||||||
|
{
|
||||||
|
var name = nameElement.GetString() ?? "";
|
||||||
|
if (!string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
_playlistIdToName[playlistId] = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Failed to get name for playlist {PlaylistId}", playlistId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<bool> ShouldRunOnStartupAsync()
|
private async Task<bool> ShouldRunOnStartupAsync()
|
||||||
{
|
{
|
||||||
// Check if any playlist has cached data from the last 24 hours
|
// Check if any playlist has cached data from the last 24 hours
|
||||||
foreach (var playlist in _spotifySettings.Value.Playlists.Where(p => p.Enabled))
|
foreach (var playlistName in _playlistIdToName.Values)
|
||||||
{
|
{
|
||||||
var cacheKey = $"spotify:missing:{playlist.SpotifyName}";
|
var cacheKey = $"spotify:missing:{playlistName}";
|
||||||
if (await _cache.ExistsAsync(cacheKey))
|
if (await _cache.ExistsAsync(cacheKey))
|
||||||
{
|
{
|
||||||
return false; // Already have recent data
|
return false; // Already have recent data
|
||||||
@@ -115,9 +149,6 @@ public class SpotifyMissingTracksFetcher : BackgroundService
|
|||||||
private async Task FetchMissingTracksAsync(CancellationToken cancellationToken)
|
private async Task FetchMissingTracksAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var settings = _spotifySettings.Value;
|
var settings = _spotifySettings.Value;
|
||||||
var jellyfinUrl = _jellyfinSettings.Value.Url;
|
|
||||||
var apiKey = _jellyfinSettings.Value.ApiKey;
|
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
var syncStart = now.Date
|
var syncStart = now.Date
|
||||||
.AddHours(settings.SyncStartHour)
|
.AddHours(settings.SyncStartHour)
|
||||||
@@ -129,20 +160,23 @@ public class SpotifyMissingTracksFetcher : BackgroundService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var playlist in settings.Playlists.Where(p => p.Enabled))
|
_logger.LogInformation("Within sync window, fetching missing tracks...");
|
||||||
|
|
||||||
|
foreach (var kvp in _playlistIdToName)
|
||||||
{
|
{
|
||||||
await FetchPlaylistMissingTracksAsync(playlist, cancellationToken);
|
await FetchPlaylistMissingTracksAsync(kvp.Value, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task FetchPlaylistMissingTracksAsync(
|
private async Task FetchPlaylistMissingTracksAsync(
|
||||||
SpotifyPlaylistConfig playlist,
|
string playlistName,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var cacheKey = $"spotify:missing:{playlist.SpotifyName}";
|
var cacheKey = $"spotify:missing:{playlistName}";
|
||||||
|
|
||||||
if (await _cache.ExistsAsync(cacheKey))
|
if (await _cache.ExistsAsync(cacheKey))
|
||||||
{
|
{
|
||||||
|
_logger.LogDebug("Cache already exists for {Playlist}", playlistName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,16 +190,19 @@ public class SpotifyMissingTracksFetcher : BackgroundService
|
|||||||
.AddMinutes(settings.SyncStartMinute);
|
.AddMinutes(settings.SyncStartMinute);
|
||||||
var syncEnd = syncStart.AddHours(settings.SyncWindowHours);
|
var syncEnd = syncStart.AddHours(settings.SyncWindowHours);
|
||||||
|
|
||||||
|
_logger.LogInformation("Searching for missing tracks file for {Playlist}", playlistName);
|
||||||
|
|
||||||
for (var time = syncStart; time <= syncEnd; time = time.AddMinutes(5))
|
for (var time = syncStart; time <= syncEnd; time = time.AddMinutes(5))
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested) break;
|
if (cancellationToken.IsCancellationRequested) break;
|
||||||
|
|
||||||
var filename = $"{playlist.SpotifyName}_missing_{time:yyyy-MM-dd_HH-mm}.json";
|
var filename = $"{playlistName}_missing_{time:yyyy-MM-dd_HH-mm}.json";
|
||||||
var url = $"{jellyfinUrl}/Viperinius.Plugin.SpotifyImport/MissingTracksFile" +
|
var url = $"{jellyfinUrl}/Viperinius.Plugin.SpotifyImport/MissingTracksFile" +
|
||||||
$"?name={Uri.EscapeDataString(filename)}&api_key={apiKey}";
|
$"?name={Uri.EscapeDataString(filename)}&api_key={apiKey}";
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_logger.LogDebug("Trying {Filename}", filename);
|
||||||
var response = await httpClient.GetAsync(url, cancellationToken);
|
var response = await httpClient.GetAsync(url, cancellationToken);
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
@@ -176,8 +213,8 @@ public class SpotifyMissingTracksFetcher : BackgroundService
|
|||||||
{
|
{
|
||||||
await _cache.SetAsync(cacheKey, tracks, TimeSpan.FromHours(24));
|
await _cache.SetAsync(cacheKey, tracks, TimeSpan.FromHours(24));
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
"Cached {Count} missing tracks for {Playlist} from {Filename}",
|
"✓ Cached {Count} missing tracks for {Playlist} from {Filename}",
|
||||||
tracks.Count, playlist.Name, filename);
|
tracks.Count, playlistName, filename);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user