Skip to content

Commit 293158d

Browse files
Jack251970jjw24
authored andcommitted
Merge pull request #3664 from Flow-Launcher/firefox_msix
Support Loading Msix FireFox Bookmarks & Fix IsRelative logic
1 parent bc019f2 commit 293158d

File tree

1 file changed

+89
-50
lines changed

1 file changed

+89
-50
lines changed

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

Lines changed: 89 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -264,83 +264,122 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
264264
/// </summary>
265265
public override List<Bookmark> GetBookmarks()
266266
{
267-
return GetBookmarksFromPath(PlacesPath);
267+
var bookmarks = new List<Bookmark>();
268+
bookmarks.AddRange(GetBookmarksFromPath(PlacesPath));
269+
bookmarks.AddRange(GetBookmarksFromPath(MsixPlacesPath));
270+
return bookmarks;
268271
}
269272

270273
/// <summary>
271-
/// Path to places.sqlite
274+
/// Path to places.sqlite of Msi installer
275+
/// E.g. C:\Users\{UserName}\AppData\Roaming\Mozilla\Firefox
276+
/// <see href="https://support.mozilla.org/en-US/kb/profiles-where-firefox-stores-user-data#w_finding-your-profile-without-opening-firefox"/>
272277
/// </summary>
273-
/// <remarks></remarks>
274278
private static string PlacesPath
275279
{
276280
get
277281
{
278282
var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox");
279-
var profileIni = Path.Combine(profileFolderPath, @"profiles.ini");
283+
return GetProfileIniPath(profileFolderPath);
284+
}
285+
}
280286

281-
if (!File.Exists(profileIni))
282-
return string.Empty;
287+
/// <summary>
288+
/// Path to places.sqlite of MSIX installer
289+
/// E.g. C:\Users\{UserName}\AppData\Local\Packages\Mozilla.Firefox_n80bbvh6b1yt2\LocalCache\Roaming\Mozilla\Firefox
290+
/// <see href="https://support.mozilla.org/en-US/kb/profiles-where-firefox-stores-user-data#w_finding-your-profile-without-opening-firefox"/>
291+
/// </summary>
292+
public static string MsixPlacesPath
293+
{
294+
get
295+
{
296+
var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
297+
var packagesPath = Path.Combine(platformPath, "Packages");
298+
try
299+
{
300+
// Search for folder with Mozilla.Firefox prefix
301+
var firefoxPackageFolder = Directory.EnumerateDirectories(packagesPath, "Mozilla.Firefox*",
302+
SearchOption.TopDirectoryOnly).FirstOrDefault();
303+
304+
// Msix FireFox not installed
305+
if (firefoxPackageFolder == null) return string.Empty;
283306

284-
// get firefox default profile directory from profiles.ini
285-
using var sReader = new StreamReader(profileIni);
286-
var ini = sReader.ReadToEnd();
307+
var profileFolderPath = Path.Combine(firefoxPackageFolder, @"LocalCache\Roaming\Mozilla\Firefox");
308+
return GetProfileIniPath(profileFolderPath);
309+
}
310+
catch
311+
{
312+
return string.Empty;
313+
}
314+
}
315+
}
287316

288-
var lines = ini.Split("\r\n").ToList();
317+
private static string GetProfileIniPath(string profileFolderPath)
318+
{
319+
var profileIni = Path.Combine(profileFolderPath, @"profiles.ini");
320+
if (!File.Exists(profileIni))
321+
return string.Empty;
289322

290-
var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty;
323+
// get firefox default profile directory from profiles.ini
324+
using var sReader = new StreamReader(profileIni);
325+
var ini = sReader.ReadToEnd();
291326

292-
if (string.IsNullOrEmpty(defaultProfileFolderNameRaw))
293-
return string.Empty;
327+
var lines = ini.Split("\r\n").ToList();
294328

295-
var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last();
329+
var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty;
296330

297-
var indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName);
331+
if (string.IsNullOrEmpty(defaultProfileFolderNameRaw))
332+
return string.Empty;
298333

299-
/*
300-
Current profiles.ini structure example as of Firefox version 69.0.1
334+
var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last();
301335

302-
[Install736426B0AF4A39CB]
303-
Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile
304-
Locked=1
336+
var indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName);
305337

306-
[Profile2]
307-
Name=newblahprofile
308-
IsRelative=0
309-
Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code.
338+
/*
339+
Current profiles.ini structure example as of Firefox version 69.0.1
310340
311-
[Profile1]
312-
Name=default
313-
IsRelative=1
314-
Path=Profiles/cydum7q4.default
315-
Default=1
341+
[Install736426B0AF4A39CB]
342+
Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile
343+
Locked=1
316344
317-
[Profile0]
318-
Name=default-release
319-
IsRelative=1
320-
Path=Profiles/7789f565.default-release
345+
[Profile2]
346+
Name=dummyprofile
347+
IsRelative=0
348+
Path=C:\t6h2yuq8.dummyprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code.
321349
322-
[General]
323-
StartWithLastProfile=1
324-
Version=2
325-
*/
326-
// Seen in the example above, the IsRelative attribute is always above the Path attribute
350+
[Profile1]
351+
Name=default
352+
IsRelative=1
353+
Path=Profiles/cydum7q4.default
354+
Default=1
327355
328-
var relativePath = Path.Combine(defaultProfileFolderName, "places.sqlite");
329-
var absoluePath = Path.Combine(profileFolderPath, relativePath);
356+
[Profile0]
357+
Name=default-release
358+
IsRelative=1
359+
Path=Profiles/7789f565.default-release
330360
331-
// If the index is out of range, it means that the default profile is in a custom location or the file is malformed
332-
// If the profile is in a custom location, we need to check
333-
if (indexOfDefaultProfileAttributePath - 1 < 0 ||
334-
indexOfDefaultProfileAttributePath - 1 >= lines.Count)
335-
{
336-
return Directory.Exists(absoluePath) ? absoluePath : relativePath;
337-
}
361+
[General]
362+
StartWithLastProfile=1
363+
Version=2
364+
*/
365+
// Seen in the example above, the IsRelative attribute is always above the Path attribute
338366

339-
var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1];
367+
var relativePath = Path.Combine(defaultProfileFolderName, "places.sqlite");
368+
var absolutePath = Path.Combine(profileFolderPath, relativePath);
340369

341-
return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0
342-
? relativePath : absoluePath;
370+
// If the index is out of range, it means that the default profile is in a custom location or the file is malformed
371+
// If the profile is in a custom location, we need to check
372+
if (indexOfDefaultProfileAttributePath - 1 < 0 ||
373+
indexOfDefaultProfileAttributePath - 1 >= lines.Count)
374+
{
375+
return Directory.Exists(absolutePath) ? absolutePath : relativePath;
343376
}
377+
378+
var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1];
379+
380+
// See above, the profile is located in a custom location, path is not relative, so IsRelative=0
381+
return (relativeAttribute == "0" || relativeAttribute == "IsRelative=0")
382+
? relativePath : absolutePath;
344383
}
345384
}
346385

0 commit comments

Comments
 (0)