mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-10 07:58:39 -05:00
Make manual mappings permanent and persist to file
- Manual mappings now have NO expiration (permanent in Redis) - Save manual mappings to /app/cache/mappings/*.json files - Load manual mappings on startup via CacheWarmingService - Manual mappings are first-order and survive restarts/cache clears - User decisions are now truly permanent
This commit is contained in:
@@ -930,19 +930,25 @@ public class AdminController : ControllerBase
|
||||
{
|
||||
if (hasJellyfinMapping)
|
||||
{
|
||||
// Store Jellyfin mapping in cache
|
||||
// Store Jellyfin mapping in cache (NO EXPIRATION - manual mappings are permanent)
|
||||
var mappingKey = $"spotify:manual-map:{decodedName}:{request.SpotifyId}";
|
||||
await _cache.SetAsync(mappingKey, request.JellyfinId!, TimeSpan.FromDays(365));
|
||||
await _cache.SetAsync(mappingKey, request.JellyfinId!);
|
||||
|
||||
// Also save to file for persistence across restarts
|
||||
await SaveManualMappingToFileAsync(decodedName, request.SpotifyId, request.JellyfinId!, null, null);
|
||||
|
||||
_logger.LogInformation("Manual Jellyfin mapping saved: {Playlist} - Spotify {SpotifyId} → Jellyfin {JellyfinId}",
|
||||
decodedName, request.SpotifyId, request.JellyfinId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store external mapping in cache
|
||||
// Store external mapping in cache (NO EXPIRATION - manual mappings are permanent)
|
||||
var externalMappingKey = $"spotify:external-map:{decodedName}:{request.SpotifyId}";
|
||||
var externalMapping = new { provider = request.ExternalProvider, id = request.ExternalId };
|
||||
await _cache.SetAsync(externalMappingKey, externalMapping, TimeSpan.FromDays(365));
|
||||
await _cache.SetAsync(externalMappingKey, externalMapping);
|
||||
|
||||
// Also save to file for persistence across restarts
|
||||
await SaveManualMappingToFileAsync(decodedName, request.SpotifyId, null, request.ExternalProvider!, request.ExternalId!);
|
||||
|
||||
_logger.LogInformation("Manual external mapping saved: {Playlist} - Spotify {SpotifyId} → {Provider} {ExternalId}",
|
||||
decodedName, request.SpotifyId, request.ExternalProvider, request.ExternalId);
|
||||
@@ -2486,6 +2492,60 @@ public class AdminController : ControllerBase
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Helper Methods
|
||||
|
||||
/// <summary>
|
||||
/// Saves a manual mapping to file for persistence across restarts.
|
||||
/// Manual mappings NEVER expire - they are permanent user decisions.
|
||||
/// </summary>
|
||||
private async Task SaveManualMappingToFileAsync(
|
||||
string playlistName,
|
||||
string spotifyId,
|
||||
string? jellyfinId,
|
||||
string? externalProvider,
|
||||
string? externalId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var mappingsDir = "/app/cache/mappings";
|
||||
Directory.CreateDirectory(mappingsDir);
|
||||
|
||||
var safeName = string.Join("_", playlistName.Split(Path.GetInvalidFileNameChars()));
|
||||
var filePath = Path.Combine(mappingsDir, $"{safeName}_mappings.json");
|
||||
|
||||
// Load existing mappings
|
||||
var mappings = new Dictionary<string, ManualMappingEntry>();
|
||||
if (System.IO.File.Exists(filePath))
|
||||
{
|
||||
var json = await System.IO.File.ReadAllTextAsync(filePath);
|
||||
mappings = JsonSerializer.Deserialize<Dictionary<string, ManualMappingEntry>>(json)
|
||||
?? new Dictionary<string, ManualMappingEntry>();
|
||||
}
|
||||
|
||||
// Add or update mapping
|
||||
mappings[spotifyId] = new ManualMappingEntry
|
||||
{
|
||||
SpotifyId = spotifyId,
|
||||
JellyfinId = jellyfinId,
|
||||
ExternalProvider = externalProvider,
|
||||
ExternalId = externalId,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
// Save back to file
|
||||
var updatedJson = JsonSerializer.Serialize(mappings, new JsonSerializerOptions { WriteIndented = true });
|
||||
await System.IO.File.WriteAllTextAsync(filePath, updatedJson);
|
||||
|
||||
_logger.LogDebug("💾 Saved manual mapping to file: {Playlist} - {SpotifyId}", playlistName, spotifyId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to save manual mapping to file for {Playlist}", playlistName);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class ManualMappingRequest
|
||||
@@ -2496,6 +2556,15 @@ public class ManualMappingRequest
|
||||
public string? ExternalId { get; set; }
|
||||
}
|
||||
|
||||
public class ManualMappingEntry
|
||||
{
|
||||
public string SpotifyId { get; set; } = "";
|
||||
public string? JellyfinId { get; set; }
|
||||
public string? ExternalProvider { get; set; }
|
||||
public string? ExternalId { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
public class ConfigUpdateRequest
|
||||
{
|
||||
public Dictionary<string, string> Updates { get; set; } = new();
|
||||
|
||||
Reference in New Issue
Block a user