using System; using System.Collections.Concurrent; using Jellyfin.Plugin.SRFPlay.Api.Models; using Jellyfin.Plugin.SRFPlay.Services.Interfaces; using Microsoft.Extensions.Logging; namespace Jellyfin.Plugin.SRFPlay.Services; /// /// Service for caching metadata from SRF API. /// public sealed class MetadataCache : IMetadataCache { private readonly ILogger _logger; private readonly ConcurrentDictionary> _mediaCompositionCache; /// /// Initializes a new instance of the class. /// /// The logger instance. public MetadataCache(ILogger logger) { _logger = logger; _mediaCompositionCache = new ConcurrentDictionary>(); } /// /// Gets cached media composition by URN. /// /// The URN. /// The cache duration in minutes. /// The cached media composition, or null if not found or expired. public MediaComposition? GetMediaComposition(string urn, int cacheDurationMinutes) { if (string.IsNullOrEmpty(urn)) { return null; } if (_mediaCompositionCache.TryGetValue(urn, out var entry)) { if (entry.IsValid(cacheDurationMinutes)) { _logger.LogDebug("Cache hit for URN: {Urn}", urn); return entry.Value; } _logger.LogDebug("Cache entry expired for URN: {Urn}", urn); } return null; } /// /// Sets media composition in cache. /// /// The URN. /// The media composition to cache. public void SetMediaComposition(string urn, MediaComposition mediaComposition) { if (string.IsNullOrEmpty(urn) || mediaComposition == null) { return; } var entry = new CacheEntry(mediaComposition); _mediaCompositionCache.AddOrUpdate(urn, entry, (key, oldValue) => entry); _logger.LogDebug("Cached media composition for URN: {Urn}", urn); } /// /// Clears all cached data. /// public void Clear() { _mediaCompositionCache.Clear(); _logger.LogInformation("Cleared metadata cache"); } /// /// Represents a cached entry with timestamp. /// /// The type of cached value. private sealed class CacheEntry { /// /// Initializes a new instance of the class. /// /// The value to cache. public CacheEntry(T value) { Value = value; Timestamp = DateTime.UtcNow; } /// /// Gets the cached value. /// public T Value { get; } /// /// Gets the timestamp when the entry was created. /// public DateTime Timestamp { get; } /// /// Checks if the cache entry is still valid. /// /// The cache duration in minutes. /// True if the entry is still valid. public bool IsValid(int cacheDurationMinutes) { var expirationTime = Timestamp.AddMinutes(cacheDurationMinutes); return DateTime.UtcNow < expirationTime; } } }