Skip to content

Commit 8bb2b50

Browse files
committed
Use concurrent way to load favorite icons for firefox
1 parent d6f40ec commit 8bb2b50

File tree

1 file changed

+52
-27
lines changed

1 file changed

+52
-27
lines changed

Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.IO;
45
using System.Linq;
6+
using System.Threading.Tasks;
57
using Flow.Launcher.Plugin.BrowserBookmark.Models;
68
using Microsoft.Data.Sqlite;
79

@@ -30,8 +32,6 @@ INNER JOIN moz_bookmarks ON (
3032
ORDER BY moz_places.visit_count DESC
3133
""";
3234

33-
private const string DbPathFormat = "Data Source={0}";
34-
3535
protected List<Bookmark> GetBookmarksFromPath(string placesPath)
3636
{
3737
// Variable to store bookmark list
@@ -117,36 +117,53 @@ protected List<Bookmark> GetBookmarksFromPath(string placesPath)
117117
return bookmarks;
118118
}
119119

120-
private void LoadFaviconsFromDb(string faviconDbPath, List<Bookmark> bookmarks)
120+
private void LoadFaviconsFromDb(string dbPath, List<Bookmark> bookmarks)
121121
{
122122
// Use a copy to avoid lock issues with the original file
123123
var tempDbPath = Path.Combine(_faviconCacheDir, $"tempfavicons_{Guid.NewGuid()}.sqlite");
124124

125125
// Use a copy to avoid lock issues with the original file
126126
try
127127
{
128-
// Use a copy to avoid lock issues with the original file
129-
File.Copy(faviconDbPath, tempDbPath, true);
130-
131-
var defaultIconPath = Path.Combine(
132-
Path.GetDirectoryName(typeof(FirefoxBookmarkLoaderBase).Assembly.Location),
133-
"bookmark.png");
134-
135-
string dbPath = string.Format(DbPathFormat, tempDbPath);
136-
using var connection = new SqliteConnection(dbPath);
137-
connection.Open();
138-
139-
// Get favicons based on bookmark URLs
140-
foreach (var bookmark in bookmarks)
128+
File.Copy(dbPath, tempDbPath, true);
129+
}
130+
catch (Exception ex)
131+
{
132+
try
141133
{
134+
if (File.Exists(tempDbPath))
135+
{
136+
File.Delete(tempDbPath);
137+
}
138+
}
139+
catch (Exception ex1)
140+
{
141+
Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex1);
142+
}
143+
Main._context.API.LogException(ClassName, $"Failed to copy favicon DB: {dbPath}", ex);
144+
return;
145+
}
146+
147+
try
148+
{
149+
// Since some bookmarks may have same favorite icon id, we need to record them to avoid duplicates
150+
var savedPaths = new ConcurrentDictionary<string, bool>();
151+
152+
// Get favicons based on bookmarks concurrently
153+
Parallel.ForEach(bookmarks, bookmark =>
154+
{
155+
// Use read-only connection to avoid locking issues
156+
var connection = new SqliteConnection($"Data Source={tempDbPath};Mode=ReadOnly");
157+
connection.Open();
158+
142159
try
143160
{
144161
if (string.IsNullOrEmpty(bookmark.Url))
145-
continue;
162+
return;
146163

147164
// Extract domain from URL
148165
if (!Uri.TryCreate(bookmark.Url, UriKind.Absolute, out Uri uri))
149-
continue;
166+
return;
150167

151168
var domain = uri.Host;
152169

@@ -166,12 +183,12 @@ ORDER BY i.width DESC -- Select largest icon available
166183

167184
using var reader = cmd.ExecuteReader();
168185
if (!reader.Read() || reader.IsDBNull(0))
169-
continue;
186+
return;
170187

171188
var imageData = (byte[])reader["data"];
172189

173190
if (imageData is not { Length: > 0 })
174-
continue;
191+
return;
175192

176193
string faviconPath;
177194
if (IsSvgData(imageData))
@@ -182,23 +199,31 @@ ORDER BY i.width DESC -- Select largest icon available
182199
{
183200
faviconPath = Path.Combine(_faviconCacheDir, $"firefox_{domain}.png");
184201
}
185-
SaveBitmapData(imageData, faviconPath);
202+
203+
// Filter out duplicate favorite icons
204+
if (savedPaths.TryAdd(faviconPath, true))
205+
{
206+
SaveBitmapData(imageData, faviconPath);
207+
}
186208

187209
bookmark.FaviconPath = faviconPath;
188210
}
189211
catch (Exception ex)
190212
{
191213
Main._context.API.LogException(ClassName, $"Failed to extract Firefox favicon: {bookmark.Url}", ex);
192214
}
193-
}
194-
195-
// https://github.com/dotnet/efcore/issues/26580
196-
SqliteConnection.ClearPool(connection);
197-
connection.Close();
215+
finally
216+
{
217+
// https://github.com/dotnet/efcore/issues/26580
218+
SqliteConnection.ClearPool(connection);
219+
connection.Close();
220+
connection.Dispose();
221+
}
222+
});
198223
}
199224
catch (Exception ex)
200225
{
201-
Main._context.API.LogException(ClassName, $"Failed to load Firefox favicon DB: {faviconDbPath}", ex);
226+
Main._context.API.LogException(ClassName, $"Failed to load Firefox favicon DB: {tempDbPath}", ex);
202227
}
203228

204229
// Delete temporary file

0 commit comments

Comments
 (0)