From abacc5c96b18648ffcc462cdba08ab80d768921e Mon Sep 17 00:00:00 2001 From: "Max T. Kristiansen" Date: Tue, 10 Sep 2024 11:29:28 +0200 Subject: [PATCH 1/3] fix: add caching provider for `PlexGraphQLClient` --- src/API/src/Program.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/API/src/Program.cs b/src/API/src/Program.cs index 980e6dd..5bcb8fb 100644 --- a/src/API/src/Program.cs +++ b/src/API/src/Program.cs @@ -43,7 +43,8 @@ static async Task Main(string[] args) builder.Services.AddCaching(opts => opts .UseHybrid("metadata", opts => opts.SQLite.DatabasePath = "metadata.sqlite") - .UseInMemory("watchlist")); + .UseInMemory("watchlist") + .UseInMemory("plex-graphql")); builder.Services.AddFetcharr(); builder.Services.AddControllers(); From 4dde276deb59e9062bf7cb5475f377e3a73814d6 Mon Sep 17 00:00:00 2001 From: "Max T. Kristiansen" Date: Tue, 10 Sep 2024 11:45:50 +0200 Subject: [PATCH 2/3] fix: increment cache size on in-memory providers --- src/Cache/InMemory/src/InMemoryCachingProvider.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Cache/InMemory/src/InMemoryCachingProvider.cs b/src/Cache/InMemory/src/InMemoryCachingProvider.cs index 5f2d696..f3da4d0 100644 --- a/src/Cache/InMemory/src/InMemoryCachingProvider.cs +++ b/src/Cache/InMemory/src/InMemoryCachingProvider.cs @@ -79,6 +79,8 @@ public override async Task SetAsync(string key, T value, TimeSpan? expiration { this._database[key] = new InMemoryCacheItem(value, _expiration); + Interlocked.Increment(ref this.CacheSize); + if(options.Value.SizeLimit > 0 && Interlocked.Read(ref this.CacheSize) >= options.Value.SizeLimit) { int itemsToRemove = (int) (Interlocked.Read(ref this.CacheSize) - options.Value.SizeLimit); From 5406de30d036efc2e924e41aaa36ec470aee314f Mon Sep 17 00:00:00 2001 From: "Max T. Kristiansen" Date: Sat, 14 Sep 2024 09:48:31 +0200 Subject: [PATCH 3/3] hotfix: handle watchlist cache evictions correctly --- src/Provider.Plex/src/PlexWatchlistClient.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Provider.Plex/src/PlexWatchlistClient.cs b/src/Provider.Plex/src/PlexWatchlistClient.cs index 58602a5..7b5c20e 100644 --- a/src/Provider.Plex/src/PlexWatchlistClient.cs +++ b/src/Provider.Plex/src/PlexWatchlistClient.cs @@ -7,6 +7,7 @@ using Flurl.Http; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Fetcharr.Provider.Plex @@ -16,12 +17,14 @@ namespace Fetcharr.Provider.Plex /// public class PlexWatchlistClient( IOptions configuration, - [FromKeyedServices("watchlist")] ICachingProvider cachingProvider) + [FromKeyedServices("watchlist")] ICachingProvider cachingProvider, + ILogger logger) { private readonly FlurlClient _client = new FlurlClient("https://metadata.provider.plex.tv/library/sections/watchlist/") .WithHeader("X-Plex-Token", configuration.Value.Plex.ApiToken) - .WithHeader("X-Plex-Client-Identifier", "fetcharr"); + .WithHeader("X-Plex-Client-Identifier", "fetcharr") + .AllowHttpStatus((int) HttpStatusCode.NotModified); /// /// If not , contains the E-Tag value of the last watchlist request. @@ -48,10 +51,17 @@ public async Task> FetchWatchlistAsync(int of CacheValue> cacheValue = await cachingProvider.GetAsync>("watchlist"); - if(cacheValue.HasValue) + // If Plex returned NotModified, but the cache is empty, it must've been evicted + // which means we have to resend the request without E-Tag caching. + if(!cacheValue.HasValue) { - return cacheValue.Value; + logger.LogInformation("Watchlist cache has been evicted; re-sending request..."); + + this.lastEtag = null; + return await this.FetchWatchlistAsync(offset, limit); } + + return cacheValue.Value; } MediaResponse watchlistContainer = await response