Fix bug where stale cache causes media player to mix up episode names
This commit is contained in:
parent
221a3f634d
commit
c54221fba2
@ -387,10 +387,9 @@ public class JellypodChannel : IChannel, IHasCacheKey, IRequiresMediaInfoCallbac
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string? GetCacheKey(string? userId)
|
public string? GetCacheKey(string? userId)
|
||||||
{
|
{
|
||||||
// Use 5-minute time buckets for cache key
|
// Include database modification time so cache invalidates when podcasts/episodes change
|
||||||
var now = DateTime.Now;
|
var lastModified = _storageService.LastModified;
|
||||||
var timeBucket = new DateTime(now.Year, now.Month, now.Day, now.Hour, (now.Minute / 5) * 5, 0);
|
return lastModified.ToString("O", CultureInfo.InvariantCulture);
|
||||||
return timeBucket.ToString("yyyy-MM-dd-HH-mm", CultureInfo.InvariantCulture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@ -10,6 +10,12 @@ namespace Jellyfin.Plugin.Jellypod.Services;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IPodcastStorageService
|
public interface IPodcastStorageService
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the cached last modification time (synchronous, for cache key generation).
|
||||||
|
/// Returns default if database hasn't been loaded yet.
|
||||||
|
/// </summary>
|
||||||
|
DateTime LastModified { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all subscribed podcasts.
|
/// Gets all subscribed podcasts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -57,4 +63,10 @@ public interface IPodcastStorageService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The base path for podcast storage.</returns>
|
/// <returns>The base path for podcast storage.</returns>
|
||||||
string GetStoragePath();
|
string GetStoragePath();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the last time the database was modified.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The last modification time, or null if unknown.</returns>
|
||||||
|
Task<DateTime?> GetLastModifiedAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,7 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable
|
|||||||
private readonly IApplicationPaths _applicationPaths;
|
private readonly IApplicationPaths _applicationPaths;
|
||||||
private readonly SemaphoreSlim _dbLock = new(1, 1);
|
private readonly SemaphoreSlim _dbLock = new(1, 1);
|
||||||
private PodcastDatabase? _cache;
|
private PodcastDatabase? _cache;
|
||||||
|
private DateTime _lastModified;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="PodcastStorageService"/> class.
|
/// Initializes a new instance of the <see cref="PodcastStorageService"/> class.
|
||||||
@ -47,6 +48,9 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable
|
|||||||
"Jellypod",
|
"Jellypod",
|
||||||
"podcasts.json");
|
"podcasts.json");
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public DateTime LastModified => _lastModified;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<IReadOnlyList<Podcast>> GetAllPodcastsAsync()
|
public async Task<IReadOnlyList<Podcast>> GetAllPodcastsAsync()
|
||||||
{
|
{
|
||||||
@ -180,6 +184,7 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable
|
|||||||
{
|
{
|
||||||
_logger.LogWarning("Database file does not exist at {Path}", DatabasePath);
|
_logger.LogWarning("Database file does not exist at {Path}", DatabasePath);
|
||||||
_cache = new PodcastDatabase();
|
_cache = new PodcastDatabase();
|
||||||
|
_lastModified = DateTime.UtcNow;
|
||||||
return _cache;
|
return _cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,6 +194,7 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable
|
|||||||
var json = await File.ReadAllTextAsync(DatabasePath).ConfigureAwait(false);
|
var json = await File.ReadAllTextAsync(DatabasePath).ConfigureAwait(false);
|
||||||
_logger.LogInformation("Read {Length} characters from database file", json.Length);
|
_logger.LogInformation("Read {Length} characters from database file", json.Length);
|
||||||
_cache = JsonSerializer.Deserialize<PodcastDatabase>(json, JsonOptions) ?? new PodcastDatabase();
|
_cache = JsonSerializer.Deserialize<PodcastDatabase>(json, JsonOptions) ?? new PodcastDatabase();
|
||||||
|
_lastModified = _cache.LastSaved;
|
||||||
_logger.LogInformation("Loaded {Count} podcasts from database", _cache.Podcasts.Count);
|
_logger.LogInformation("Loaded {Count} podcasts from database", _cache.Podcasts.Count);
|
||||||
return _cache;
|
return _cache;
|
||||||
}
|
}
|
||||||
@ -196,6 +202,7 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable
|
|||||||
{
|
{
|
||||||
_logger.LogError(ex, "Failed to load podcast database, starting fresh");
|
_logger.LogError(ex, "Failed to load podcast database, starting fresh");
|
||||||
_cache = new PodcastDatabase();
|
_cache = new PodcastDatabase();
|
||||||
|
_lastModified = DateTime.UtcNow;
|
||||||
return _cache;
|
return _cache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,6 +218,7 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
db.LastSaved = DateTime.UtcNow;
|
db.LastSaved = DateTime.UtcNow;
|
||||||
|
_lastModified = db.LastSaved;
|
||||||
var json = JsonSerializer.Serialize(db, JsonOptions);
|
var json = JsonSerializer.Serialize(db, JsonOptions);
|
||||||
await File.WriteAllTextAsync(DatabasePath, json).ConfigureAwait(false);
|
await File.WriteAllTextAsync(DatabasePath, json).ConfigureAwait(false);
|
||||||
_cache = db;
|
_cache = db;
|
||||||
@ -261,6 +269,13 @@ public sealed class PodcastStorageService : IPodcastStorageService, IDisposable
|
|||||||
return ".mp3";
|
return ".mp3";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<DateTime?> GetLastModifiedAsync()
|
||||||
|
{
|
||||||
|
var db = await LoadDatabaseAsync().ConfigureAwait(false);
|
||||||
|
return db.LastSaved;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user