diff --git a/Jellyfin.Plugin.Jellypod/Channels/JellypodChannel.cs b/Jellyfin.Plugin.Jellypod/Channels/JellypodChannel.cs index eff9018..5ab64b2 100644 --- a/Jellyfin.Plugin.Jellypod/Channels/JellypodChannel.cs +++ b/Jellyfin.Plugin.Jellypod/Channels/JellypodChannel.cs @@ -387,10 +387,9 @@ public class JellypodChannel : IChannel, IHasCacheKey, IRequiresMediaInfoCallbac /// public string? GetCacheKey(string? userId) { - // Use 5-minute time buckets for cache key - var now = DateTime.Now; - var timeBucket = new DateTime(now.Year, now.Month, now.Day, now.Hour, (now.Minute / 5) * 5, 0); - return timeBucket.ToString("yyyy-MM-dd-HH-mm", CultureInfo.InvariantCulture); + // Include database modification time so cache invalidates when podcasts/episodes change + var lastModified = _storageService.LastModified; + return lastModified.ToString("O", CultureInfo.InvariantCulture); } /// diff --git a/Jellyfin.Plugin.Jellypod/Services/IPodcastStorageService.cs b/Jellyfin.Plugin.Jellypod/Services/IPodcastStorageService.cs index cb01e09..ac3af64 100644 --- a/Jellyfin.Plugin.Jellypod/Services/IPodcastStorageService.cs +++ b/Jellyfin.Plugin.Jellypod/Services/IPodcastStorageService.cs @@ -10,6 +10,12 @@ namespace Jellyfin.Plugin.Jellypod.Services; /// public interface IPodcastStorageService { + /// + /// Gets the cached last modification time (synchronous, for cache key generation). + /// Returns default if database hasn't been loaded yet. + /// + DateTime LastModified { get; } + /// /// Gets all subscribed podcasts. /// @@ -57,4 +63,10 @@ public interface IPodcastStorageService /// /// The base path for podcast storage. string GetStoragePath(); + + /// + /// Gets the last time the database was modified. + /// + /// The last modification time, or null if unknown. + Task GetLastModifiedAsync(); } diff --git a/Jellyfin.Plugin.Jellypod/Services/PodcastStorageService.cs b/Jellyfin.Plugin.Jellypod/Services/PodcastStorageService.cs index 249f2c4..129db9d 100644 --- a/Jellyfin.Plugin.Jellypod/Services/PodcastStorageService.cs +++ b/Jellyfin.Plugin.Jellypod/Services/PodcastStorageService.cs @@ -28,6 +28,7 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable private readonly IApplicationPaths _applicationPaths; private readonly SemaphoreSlim _dbLock = new(1, 1); private PodcastDatabase? _cache; + private DateTime _lastModified; /// /// Initializes a new instance of the class. @@ -47,6 +48,9 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable "Jellypod", "podcasts.json"); + /// + public DateTime LastModified => _lastModified; + /// public async Task> GetAllPodcastsAsync() { @@ -180,6 +184,7 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable { _logger.LogWarning("Database file does not exist at {Path}", DatabasePath); _cache = new PodcastDatabase(); + _lastModified = DateTime.UtcNow; return _cache; } @@ -189,6 +194,7 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable var json = await File.ReadAllTextAsync(DatabasePath).ConfigureAwait(false); _logger.LogInformation("Read {Length} characters from database file", json.Length); _cache = JsonSerializer.Deserialize(json, JsonOptions) ?? new PodcastDatabase(); + _lastModified = _cache.LastSaved; _logger.LogInformation("Loaded {Count} podcasts from database", _cache.Podcasts.Count); return _cache; } @@ -196,6 +202,7 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable { _logger.LogError(ex, "Failed to load podcast database, starting fresh"); _cache = new PodcastDatabase(); + _lastModified = DateTime.UtcNow; return _cache; } } @@ -211,6 +218,7 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable } db.LastSaved = DateTime.UtcNow; + _lastModified = db.LastSaved; var json = JsonSerializer.Serialize(db, JsonOptions); await File.WriteAllTextAsync(DatabasePath, json).ConfigureAwait(false); _cache = db; @@ -261,6 +269,13 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable return ".mp3"; } + /// + public async Task GetLastModifiedAsync() + { + var db = await LoadDatabaseAsync().ConfigureAwait(false); + return db.LastSaved; + } + /// public void Dispose() {