@@ -29,64 +29,41 @@ var s when s.Contains("Firefox") => await GetFirefoxFaviconAsync(bookmark, token
29
29
} ;
30
30
}
31
31
32
- private async Task < byte [ ] ? > GetChromiumFaviconAsync ( Bookmark bookmark , CancellationToken token )
32
+ private Task < byte [ ] ? > GetChromiumFaviconAsync ( Bookmark bookmark , CancellationToken token )
33
33
{
34
- var dbPath = Path . Combine ( bookmark . ProfilePath , "Favicons" ) ;
35
- if ( ! File . Exists ( dbPath ) ) return null ;
34
+ const string query = @"
35
+ SELECT b.image_data FROM favicon_bitmaps b
36
+ JOIN icon_mapping m ON b.icon_id = m.icon_id
37
+ WHERE m.page_url = @url
38
+ ORDER BY b.width DESC LIMIT 1" ;
36
39
37
- var tempDbPath = Path . Combine ( _tempPath , $ "chromium_favicons_{ Guid . NewGuid ( ) } .db") ;
38
- try
39
- {
40
- File . Copy ( dbPath , tempDbPath , true ) ;
41
-
42
- var query = @"
43
- SELECT b.image_data FROM favicon_bitmaps b
44
- JOIN icon_mapping m ON b.icon_id = m.icon_id
45
- WHERE m.page_url = @url
46
- ORDER BY b.width DESC LIMIT 1" ;
47
-
48
- var connectionString = $ "Data Source={ tempDbPath } ;Mode=ReadOnly;Pooling=false;";
49
- await using var connection = new SqliteConnection ( connectionString ) ;
50
- await connection . OpenAsync ( token ) ;
51
- await using var cmd = connection . CreateCommand ( ) ;
52
- cmd . CommandText = query ;
53
- cmd . Parameters . AddWithValue ( "@url" , bookmark . Url ) ;
54
-
55
- var result = await cmd . ExecuteScalarAsync ( token ) ;
56
- if ( result is byte [ ] data && data . Length > 0 )
57
- {
58
- _context . API . LogDebug ( nameof ( LocalFaviconExtractor ) , $ "Extracted { data . Length } bytes for { bookmark . Url } from Chromium DB.") ;
59
- return data ;
60
- }
61
- return null ;
62
- }
63
- catch ( Exception ex )
64
- {
65
- _context . API . LogException ( nameof ( LocalFaviconExtractor ) , $ "Failed to extract Chromium favicon for { bookmark . Url } from { bookmark . Source } ", ex ) ;
66
- return null ;
67
- }
68
- finally
69
- {
70
- CleanupTempFiles ( tempDbPath ) ;
71
- }
40
+ return GetFaviconFromDbAsync ( bookmark , "Favicons" , query , null , token ) ;
72
41
}
73
42
74
- private async Task < byte [ ] ? > GetFirefoxFaviconAsync ( Bookmark bookmark , CancellationToken token )
43
+ private Task < byte [ ] ? > GetFirefoxFaviconAsync ( Bookmark bookmark , CancellationToken token )
75
44
{
76
- var dbPath = Path . Combine ( bookmark . ProfilePath , "favicons.sqlite" ) ;
77
- if ( ! File . Exists ( dbPath ) ) return null ;
45
+ const string query = @"
46
+ SELECT i.data FROM moz_icons i
47
+ JOIN moz_icons_to_pages ip ON i.id = ip.icon_id
48
+ JOIN moz_pages_w_icons p ON ip.page_id = p.id
49
+ WHERE p.page_url = @url
50
+ ORDER BY i.width DESC LIMIT 1" ;
51
+
52
+ return GetFaviconFromDbAsync ( bookmark , "favicons.sqlite" , query , PostProcessFirefoxFavicon , token ) ;
53
+ }
78
54
79
- var tempDbPath = Path . Combine ( _tempPath , $ "firefox_favicons_{ Guid . NewGuid ( ) } .sqlite") ;
55
+ private async Task < byte [ ] ? > GetFaviconFromDbAsync ( Bookmark bookmark , string dbFileName , string query ,
56
+ Func < byte [ ] , CancellationToken , Task < byte [ ] > > ? postProcessor , CancellationToken token )
57
+ {
58
+ var dbPath = Path . Combine ( bookmark . ProfilePath , dbFileName ) ;
59
+ if ( ! File . Exists ( dbPath ) )
60
+ return null ;
61
+
62
+ var tempDbPath = Path . Combine ( _tempPath , $ "{ Path . GetFileNameWithoutExtension ( dbFileName ) } _{ Guid . NewGuid ( ) } { Path . GetExtension ( dbFileName ) } ") ;
63
+
80
64
try
81
65
{
82
66
File . Copy ( dbPath , tempDbPath , true ) ;
83
-
84
- var query = @"
85
- SELECT i.data FROM moz_icons i
86
- JOIN moz_icons_to_pages ip ON i.id = ip.icon_id
87
- JOIN moz_pages_w_icons p ON ip.page_id = p.id
88
- WHERE p.page_url = @url
89
- ORDER BY i.width DESC LIMIT 1" ;
90
67
91
68
var connectionString = $ "Data Source={ tempDbPath } ;Mode=ReadOnly;Pooling=false;";
92
69
await using var connection = new SqliteConnection ( connectionString ) ;
@@ -95,27 +72,16 @@ SELECT i.data FROM moz_icons i
95
72
cmd . CommandText = query ;
96
73
cmd . Parameters . AddWithValue ( "@url" , bookmark . Url ) ;
97
74
98
- var result = await cmd . ExecuteScalarAsync ( token ) ;
99
- if ( result is not byte [ ] imageData || imageData . Length == 0 )
75
+ if ( await cmd . ExecuteScalarAsync ( token ) is not byte [ ] data || data . Length == 0 )
100
76
return null ;
101
-
102
- _context . API . LogDebug ( nameof ( LocalFaviconExtractor ) , $ "Extracted { imageData . Length } bytes for { bookmark . Url } from Firefox DB.") ;
103
77
104
- // Handle old GZipped favicons
105
- if ( imageData . Length > 2 && imageData [ 0 ] == 0x1f && imageData [ 1 ] == 0x8b )
106
- {
107
- await using var inputStream = new MemoryStream ( imageData ) ;
108
- await using var gZipStream = new GZipStream ( inputStream , CompressionMode . Decompress ) ;
109
- await using var outputStream = new MemoryStream ( ) ;
110
- await gZipStream . CopyToAsync ( outputStream , token ) ;
111
- return outputStream . ToArray ( ) ;
112
- }
78
+ _context . API . LogDebug ( nameof ( LocalFaviconExtractor ) , $ "Extracted { data . Length } bytes for { bookmark . Url } from { dbFileName } .") ;
113
79
114
- return imageData ;
80
+ return postProcessor != null ? await postProcessor ( data , token ) : data ;
115
81
}
116
82
catch ( Exception ex )
117
83
{
118
- _context . API . LogException ( nameof ( LocalFaviconExtractor ) , $ "Failed to extract Firefox favicon for { bookmark . Url } from { bookmark . Source } ", ex ) ;
84
+ _context . API . LogException ( nameof ( LocalFaviconExtractor ) , $ "Failed to extract favicon for { bookmark . Url } from { bookmark . Source } 's { dbFileName } ", ex ) ;
119
85
return null ;
120
86
}
121
87
finally
@@ -124,6 +90,21 @@ SELECT i.data FROM moz_icons i
124
90
}
125
91
}
126
92
93
+ private async Task < byte [ ] > PostProcessFirefoxFavicon ( byte [ ] imageData , CancellationToken token )
94
+ {
95
+ // Handle old GZipped favicons
96
+ if ( imageData . Length > 2 && imageData [ 0 ] == 0x1f && imageData [ 1 ] == 0x8b )
97
+ {
98
+ await using var inputStream = new MemoryStream ( imageData ) ;
99
+ await using var gZipStream = new GZipStream ( inputStream , CompressionMode . Decompress ) ;
100
+ await using var outputStream = new MemoryStream ( ) ;
101
+ await gZipStream . CopyToAsync ( outputStream , token ) ;
102
+ return outputStream . ToArray ( ) ;
103
+ }
104
+
105
+ return imageData ;
106
+ }
107
+
127
108
private void CleanupTempFiles ( string mainTempDbPath )
128
109
{
129
110
// This method ensures that the main temp file and any of its associated files
0 commit comments