1
+ #nullable enable
1
2
using Flow . Launcher . Plugin . BrowserBookmarks . Models ;
2
3
using System ;
3
4
using System . Collections . Concurrent ;
4
5
using System . Collections . Generic ;
5
6
using System . IO ;
6
7
using System . Linq ;
7
- using System . Text . RegularExpressions ;
8
8
using System . Threading ;
9
9
using System . Threading . Tasks ;
10
10
@@ -14,14 +14,16 @@ public class BookmarkLoaderService
14
14
{
15
15
private readonly PluginInitContext _context ;
16
16
private readonly Settings _settings ;
17
+ private readonly string _tempPath ;
17
18
18
19
// This will hold the actual paths to the bookmark files for the watcher service
19
20
public List < string > DiscoveredBookmarkFiles { get ; } = new ( ) ;
20
21
21
- public BookmarkLoaderService ( PluginInitContext context , Settings settings )
22
+ public BookmarkLoaderService ( PluginInitContext context , Settings settings , string tempPath )
22
23
{
23
24
_context = context ;
24
25
_settings = settings ;
26
+ _tempPath = tempPath ;
25
27
}
26
28
27
29
public async Task < List < Bookmark > > LoadBookmarksAsync ( CancellationToken cancellationToken )
@@ -45,7 +47,7 @@ public async Task<List<Bookmark>> LoadBookmarksAsync(CancellationToken cancellat
45
47
}
46
48
catch ( Exception e )
47
49
{
48
- _context . API . LogException ( nameof ( BookmarkLoaderService ) , $ "Failed to load bookmarks from a source .", e ) ;
50
+ _context . API . LogException ( nameof ( BookmarkLoaderService ) , $ "Failed to load bookmarks from { loader . Name } .", e ) ;
49
51
}
50
52
} ) ;
51
53
@@ -72,22 +74,41 @@ private IEnumerable<IBookmarkLoader> GetBookmarkLoaders()
72
74
yield return new ChromiumBookmarkLoader ( "Microsoft Edge" , path , logAction , DiscoveredBookmarkFiles ) ;
73
75
}
74
76
77
+ if ( _settings . LoadChromiumBookmark )
78
+ {
79
+ var path = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) , @"Chromium\User Data" ) ;
80
+ if ( Directory . Exists ( path ) )
81
+ yield return new ChromiumBookmarkLoader ( "Chromium" , path , logAction , DiscoveredBookmarkFiles ) ;
82
+ }
83
+
75
84
if ( _settings . LoadFirefoxBookmark )
76
85
{
77
- // Standard MSI installer path
78
- var placesPath = GetFirefoxPlacesPathFromProfileDir ( Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . ApplicationData ) , @"Mozilla\Firefox" ) ) ;
86
+ string ? placesPath = null ;
87
+ try
88
+ {
89
+ placesPath = FirefoxProfileFinder . GetFirefoxPlacesPath ( ) ;
90
+ }
91
+ catch ( Exception ex )
92
+ {
93
+ _context . API . LogException ( nameof ( BookmarkLoaderService ) , "Failed to find Firefox profile" , ex ) ;
94
+ }
79
95
if ( ! string . IsNullOrEmpty ( placesPath ) )
80
96
{
81
- // Do not add Firefox places.sqlite to the watcher as it's updated constantly for history.
82
- yield return new FirefoxBookmarkLoader ( "Firefox" , placesPath , _context . CurrentPluginMetadata . PluginCacheDirectoryPath , logAction ) ;
97
+ yield return new FirefoxBookmarkLoader ( "Firefox" , placesPath , _tempPath , logAction ) ;
83
98
}
84
99
85
- // MSIX (Microsoft Store) installer path
86
- var msixPlacesPath = GetFirefoxMsixPlacesPath ( ) ;
100
+ string ? msixPlacesPath = null ;
101
+ try
102
+ {
103
+ msixPlacesPath = FirefoxProfileFinder . GetFirefoxMsixPlacesPath ( ) ;
104
+ }
105
+ catch ( Exception ex )
106
+ {
107
+ _context . API . LogException ( nameof ( BookmarkLoaderService ) , "Failed to find Firefox MSIX package" , ex ) ;
108
+ }
87
109
if ( ! string . IsNullOrEmpty ( msixPlacesPath ) )
88
110
{
89
- // Do not add Firefox places.sqlite to the watcher as it's updated constantly for history.
90
- yield return new FirefoxBookmarkLoader ( "Firefox (Store)" , msixPlacesPath , _context . CurrentPluginMetadata . PluginCacheDirectoryPath , logAction ) ;
111
+ yield return new FirefoxBookmarkLoader ( "Firefox (Store)" , msixPlacesPath , _tempPath , logAction ) ;
91
112
}
92
113
}
93
114
@@ -105,73 +126,19 @@ private IEnumerable<IBookmarkLoader> GetBookmarkLoaders()
105
126
yield return loader ;
106
127
}
107
128
}
108
-
129
+
109
130
private IBookmarkLoader CreateCustomFirefoxLoader ( string name , string dataDirectoryPath )
110
131
{
111
132
var logAction = ( string tag , string msg , Exception ? ex ) => _context . API . LogException ( tag , msg , ex ) ;
112
133
// Custom Firefox paths might point to the root profile dir (e.g. ...\Mozilla\Firefox)
113
- var placesPath = GetFirefoxPlacesPathFromProfileDir ( dataDirectoryPath ) ;
134
+ var placesPath = FirefoxProfileFinder . GetPlacesPathFromProfileDir ( dataDirectoryPath ) ;
114
135
if ( string . IsNullOrEmpty ( placesPath ) )
115
136
{
116
137
// Or they might point directly to a profile folder (e.g. ...\Profiles\xyz.default-release)
117
138
placesPath = Path . Combine ( dataDirectoryPath , "places.sqlite" ) ;
118
139
}
119
-
120
- // Do not add Firefox places.sqlite to the watcher as it's updated constantly for history.
121
- return new FirefoxBookmarkLoader ( name , placesPath , _context . CurrentPluginMetadata . PluginCacheDirectoryPath , logAction ) ;
122
- }
123
-
124
- private string GetFirefoxMsixPlacesPath ( )
125
- {
126
- var packagesPath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) , "Packages" ) ;
127
- if ( ! Directory . Exists ( packagesPath ) ) return string . Empty ;
128
140
129
- try
130
- {
131
- var firefoxPackageFolder = Directory . EnumerateDirectories ( packagesPath , "Mozilla.Firefox*" , SearchOption . TopDirectoryOnly ) . FirstOrDefault ( ) ;
132
- if ( firefoxPackageFolder == null ) return string . Empty ;
133
-
134
- var profileFolderPath = Path . Combine ( firefoxPackageFolder , @"LocalCache\Roaming\Mozilla\Firefox" ) ;
135
- return GetFirefoxPlacesPathFromProfileDir ( profileFolderPath ) ;
136
- }
137
- catch ( Exception ex )
138
- {
139
- _context . API . LogException ( nameof ( BookmarkLoaderService ) , "Failed to find Firefox MSIX package" , ex ) ;
140
- return string . Empty ;
141
- }
142
- }
143
-
144
- private static string GetFirefoxPlacesPathFromProfileDir ( string profileFolderPath )
145
- {
146
- var profileIni = Path . Combine ( profileFolderPath , @"profiles.ini" ) ;
147
- if ( ! File . Exists ( profileIni ) )
148
- return string . Empty ;
149
-
150
- try
151
- {
152
- var iniContent = File . ReadAllText ( profileIni ) ;
153
- var profileSectionMatch = Regex . Match ( iniContent , @"\[Profile[^\]]+\]\s*Name=default-release[\s\S]+?Path=([^\r\n]+)[\s\S]+?Default=1" , RegexOptions . IgnoreCase ) ;
154
- if ( ! profileSectionMatch . Success )
155
- {
156
- profileSectionMatch = Regex . Match ( iniContent , @"\[Profile[^\]]+\][\s\S]+?Path=([^\r\n]+)[\s\S]+?Default=1" , RegexOptions . IgnoreCase ) ;
157
- }
158
- if ( ! profileSectionMatch . Success )
159
- {
160
- profileSectionMatch = Regex . Match ( iniContent , @"\[Profile[^\]]+\][\s\S]+?Path=([^\r\n]+)" ) ;
161
- }
162
- if ( ! profileSectionMatch . Success ) return string . Empty ;
163
-
164
- var path = profileSectionMatch . Groups [ 1 ] . Value ;
165
- var isRelative = ! path . Contains ( ':' ) ;
166
-
167
- var profilePath = isRelative ? Path . Combine ( profileFolderPath , path . Replace ( '/' , Path . DirectorySeparatorChar ) ) : path ;
168
- var placesDb = Path . Combine ( profilePath , "places.sqlite" ) ;
169
-
170
- return File . Exists ( placesDb ) ? placesDb : string . Empty ;
171
- }
172
- catch
173
- {
174
- return string . Empty ;
175
- }
141
+ // Do not add Firefox places.sqlite to the watcher as it's updated constantly for history.
142
+ return new FirefoxBookmarkLoader ( name , placesPath , _tempPath , logAction ) ;
176
143
}
177
144
}
0 commit comments