Skip to content

Commit 84a47b4

Browse files
committed
wait 12 hours before retrying failed fetches
1 parent 697cc7f commit 84a47b4

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed

Plugins/Flow.Launcher.Plugin.BrowserBookmark/Services/FaviconService.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public partial class FaviconService : IDisposable
2828
private readonly LocalFaviconExtractor _localExtractor;
2929
private readonly CancellationTokenSource _cts = new();
3030
private readonly ConcurrentDictionary<string, Task<string?>> _ongoingFetches = new(StringComparer.OrdinalIgnoreCase);
31+
private readonly ConcurrentDictionary<string, DateTime> _failedFetches = new(StringComparer.OrdinalIgnoreCase);
3132

3233
[GeneratedRegex("<link[^>]+?>", RegexOptions.IgnoreCase | RegexOptions.Compiled, "en-US")]
3334
private static partial Regex LinkTagRegex();
@@ -44,6 +45,7 @@ private record struct FaviconCandidate(string Url, int Score);
4445
private record struct FetchResult(string? TempPath, int Size);
4546
private const int MaxFaviconBytes = 250 * 1024;
4647
private const int TargetIconSize = 48;
48+
private static readonly TimeSpan FailedFaviconCooldown = TimeSpan.FromHours(12); // How long to wait before retrying a failed favicon
4749

4850
public FaviconService(PluginInitContext context, Settings settings, string tempPath)
4951
{
@@ -114,6 +116,15 @@ await Parallel.ForEachAsync(bookmarks, options, async (bookmark, token) =>
114116
return Task.FromResult<string?>(null);
115117
}
116118
var authority = url.GetLeftPart(UriPartial.Authority);
119+
120+
// Check if this domain recently failed to provide a favicon
121+
if (_failedFetches.TryGetValue(authority, out var lastAttemptTime) &&
122+
(DateTime.UtcNow - lastAttemptTime < FailedFaviconCooldown))
123+
{
124+
_context.API.LogDebug(nameof(FaviconService), $"Skipping favicon fetch for {authority} due to recent failure (cooldown active).");
125+
return Task.FromResult<string?>(null);
126+
}
127+
117128
return _ongoingFetches.GetOrAdd(authority, key => FetchAndCacheFaviconAsync(new Uri(key)));
118129
}
119130

@@ -139,6 +150,7 @@ private static string GetCachePath(string url, string cacheDir)
139150

140151
FetchResult icoResult = default;
141152
FetchResult htmlResult = default;
153+
bool fetchAttempted = false;
142154

143155
try
144156
{
@@ -156,6 +168,7 @@ private static string GetCachePath(string url, string cacheDir)
156168
{
157169
// A task finished with a good icon. We can cancel the other one.
158170
linkedCts.Cancel();
171+
fetchAttempted = true; // Mark as attempted, but potentially successful
159172
break;
160173
}
161174
}
@@ -170,6 +183,7 @@ private static string GetCachePath(string url, string cacheDir)
170183
{
171184
File.Move(bestResult.TempPath, cachePath, true);
172185
_context.API.LogDebug(nameof(FaviconService), $"Favicon for {urlString} cached successfully.");
186+
_failedFetches.TryRemove(urlString, out _); // Remove from blacklist on success
173187
return cachePath;
174188
}
175189

@@ -178,12 +192,19 @@ private static string GetCachePath(string url, string cacheDir)
178192
catch (Exception ex)
179193
{
180194
_context.API.LogException(nameof(FaviconService), $"Error in favicon fetch for {urlString}", ex);
195+
fetchAttempted = true; // Mark as attempted and failed
181196
}
182197
finally
183198
{
184199
if (icoResult.TempPath != null && File.Exists(icoResult.TempPath)) File.Delete(icoResult.TempPath);
185200
if (htmlResult.TempPath != null && File.Exists(htmlResult.TempPath)) File.Delete(htmlResult.TempPath);
186201
_ongoingFetches.TryRemove(urlString, out _);
202+
203+
// If fetch was attempted but no favicon found or an exception occurred, add to failed fetches
204+
if (fetchAttempted && !File.Exists(cachePath))
205+
{
206+
_failedFetches[urlString] = DateTime.UtcNow;
207+
}
187208
}
188209

189210
return null;
@@ -521,6 +542,7 @@ public void Dispose()
521542
{
522543
_cts.Cancel();
523544
_ongoingFetches.Clear();
545+
_failedFetches.Clear(); // Clear failed fetches on dispose
524546
_httpClient.Dispose();
525547
_cts.Dispose();
526548
GC.SuppressFinalize(this);

0 commit comments

Comments
 (0)