-
-
Notifications
You must be signed in to change notification settings - Fork 461
Support Loading Msix FireFox Bookmarks & Fix IsRelative logic #3664
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
33a5ca8
57470a9
f59e239
c323646
6f516ee
b6cca45
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,10 +24,10 @@ | |
|
|
||
| // Updated query - removed favicon_id column | ||
| private const string QueryAllBookmarks = """ | ||
| SELECT moz_places.url, moz_bookmarks.title | ||
| FROM moz_places | ||
| INNER JOIN moz_bookmarks ON ( | ||
| moz_bookmarks.fk NOT NULL AND moz_bookmarks.title NOT NULL AND moz_bookmarks.fk = moz_places.id | ||
| ) | ||
| ORDER BY moz_places.visit_count DESC | ||
| """; | ||
|
|
@@ -80,12 +80,12 @@ | |
| // Load favicons after loading bookmarks | ||
| if (Main._settings.EnableFavicons) | ||
| { | ||
| var faviconDbPath = Path.Combine(Path.GetDirectoryName(placesPath), "favicons.sqlite"); | ||
| if (File.Exists(faviconDbPath)) | ||
| { | ||
| Main._context.API.StopwatchLogInfo(ClassName, $"Load {bookmarks.Count} favicons cost", () => | ||
| { | ||
| LoadFaviconsFromDb(faviconDbPath, bookmarks); | ||
| }); | ||
| } | ||
| } | ||
|
|
@@ -264,83 +264,121 @@ | |
| /// </summary> | ||
| public override List<Bookmark> GetBookmarks() | ||
| { | ||
| return GetBookmarksFromPath(PlacesPath); | ||
| var bookmarks1 = GetBookmarksFromPath(PlacesPath); | ||
| var bookmarks2 = GetBookmarksFromPath(MsixPlacesPath); | ||
| return bookmarks1.Concat(bookmarks2).ToList(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Path to places.sqlite | ||
| /// Path to places.sqlite of Msi installer | ||
| /// E.g. C:\Users\{UserName}\AppData\Roaming\Mozilla\Firefox | ||
| /// <see href="https://support.mozilla.org/en-US/kb/profiles-where-firefox-stores-user-data#w_finding-your-profile-without-opening-firefox"/> | ||
| /// </summary> | ||
| /// <remarks></remarks> | ||
| private static string PlacesPath | ||
| { | ||
| get | ||
| { | ||
| var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox"); | ||
| var profileIni = Path.Combine(profileFolderPath, @"profiles.ini"); | ||
| return GetProfileIniPath(profileFolderPath); | ||
| } | ||
| } | ||
|
|
||
| if (!File.Exists(profileIni)) | ||
| return string.Empty; | ||
| /// <summary> | ||
| /// Path to places.sqlite of MSIX installer | ||
| /// E.g. C:\Users\{UserName}\AppData\Local\Packages\Mozilla.Firefox_n80bbvh6b1yt2\LocalCache\Roaming\Mozilla\Firefox | ||
| /// <see href="https://support.mozilla.org/en-US/kb/profiles-where-firefox-stores-user-data#w_finding-your-profile-without-opening-firefox"/> | ||
| /// </summary> | ||
| public static string MsixPlacesPath | ||
| { | ||
| get | ||
| { | ||
| var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); | ||
| var packagesPath = Path.Combine(platformPath, "Packages"); | ||
| try | ||
| { | ||
| // Search for folder with Mozilla.Firefox prefix | ||
| var firefoxPackageFolder = Directory.EnumerateDirectories(packagesPath, "Mozilla.Firefox*", | ||
| SearchOption.TopDirectoryOnly).FirstOrDefault(); | ||
|
|
||
| // Msix FireFox not installed | ||
| if (firefoxPackageFolder == null) return string.Empty; | ||
|
|
||
| // get firefox default profile directory from profiles.ini | ||
| using var sReader = new StreamReader(profileIni); | ||
| var ini = sReader.ReadToEnd(); | ||
| var profileFolderPath = Path.Combine(firefoxPackageFolder, @"LocalCache\Roaming\Mozilla\Firefox"); | ||
| return GetProfileIniPath(profileFolderPath); | ||
| } | ||
| catch | ||
| { | ||
| return string.Empty; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| var lines = ini.Split("\r\n").ToList(); | ||
| private static string GetProfileIniPath(string profileFolderPath) | ||
| { | ||
| var profileIni = Path.Combine(profileFolderPath, @"profiles.ini"); | ||
| if (!File.Exists(profileIni)) | ||
| return string.Empty; | ||
|
|
||
| var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty; | ||
| // get firefox default profile directory from profiles.ini | ||
| using var sReader = new StreamReader(profileIni); | ||
| var ini = sReader.ReadToEnd(); | ||
|
|
||
| if (string.IsNullOrEmpty(defaultProfileFolderNameRaw)) | ||
| return string.Empty; | ||
| var lines = ini.Split("\r\n").ToList(); | ||
|
|
||
| var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last(); | ||
| var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty; | ||
|
|
||
| var indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName); | ||
| if (string.IsNullOrEmpty(defaultProfileFolderNameRaw)) | ||
| return string.Empty; | ||
|
|
||
| /* | ||
| Current profiles.ini structure example as of Firefox version 69.0.1 | ||
| var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last(); | ||
|
|
||
| [Install736426B0AF4A39CB] | ||
| 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 | ||
| Locked=1 | ||
| var indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName); | ||
|
|
||
| [Profile2] | ||
| Name=newblahprofile | ||
| IsRelative=0 | ||
| 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. | ||
| /* | ||
| Current profiles.ini structure example as of Firefox version 69.0.1 | ||
|
|
||
| [Profile1] | ||
| Name=default | ||
| IsRelative=1 | ||
| Path=Profiles/cydum7q4.default | ||
| Default=1 | ||
| [Install736426B0AF4A39CB] | ||
| 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 | ||
| Locked=1 | ||
|
|
||
| [Profile0] | ||
| Name=default-release | ||
| IsRelative=1 | ||
| Path=Profiles/7789f565.default-release | ||
| [Profile2] | ||
| Name=newblahprofile | ||
|
||
| IsRelative=0 | ||
| 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. | ||
|
|
||
| [General] | ||
| StartWithLastProfile=1 | ||
| Version=2 | ||
| */ | ||
| // Seen in the example above, the IsRelative attribute is always above the Path attribute | ||
| [Profile1] | ||
| Name=default | ||
| IsRelative=1 | ||
| Path=Profiles/cydum7q4.default | ||
| Default=1 | ||
|
|
||
| var relativePath = Path.Combine(defaultProfileFolderName, "places.sqlite"); | ||
| var absoluePath = Path.Combine(profileFolderPath, relativePath); | ||
| [Profile0] | ||
| Name=default-release | ||
| IsRelative=1 | ||
| Path=Profiles/7789f565.default-release | ||
|
|
||
| // If the index is out of range, it means that the default profile is in a custom location or the file is malformed | ||
| // If the profile is in a custom location, we need to check | ||
| if (indexOfDefaultProfileAttributePath - 1 < 0 || | ||
| indexOfDefaultProfileAttributePath - 1 >= lines.Count) | ||
| { | ||
| return Directory.Exists(absoluePath) ? absoluePath : relativePath; | ||
| } | ||
| [General] | ||
| StartWithLastProfile=1 | ||
| Version=2 | ||
| */ | ||
| // Seen in the example above, the IsRelative attribute is always above the Path attribute | ||
|
|
||
| var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1]; | ||
| var relativePath = Path.Combine(defaultProfileFolderName, "places.sqlite"); | ||
| var absoluePath = Path.Combine(profileFolderPath, relativePath); | ||
|
|
||
| return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 | ||
| ? relativePath : absoluePath; | ||
| // If the index is out of range, it means that the default profile is in a custom location or the file is malformed | ||
| // If the profile is in a custom location, we need to check | ||
| if (indexOfDefaultProfileAttributePath - 1 < 0 || | ||
| indexOfDefaultProfileAttributePath - 1 >= lines.Count) | ||
| { | ||
| return Directory.Exists(absoluePath) ? absoluePath : relativePath; | ||
Jack251970 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1]; | ||
|
|
||
| // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 | ||
| return (relativeAttribute == "0" || relativeAttribute == "IsRelative=0") | ||
Jack251970 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ? relativePath : absoluePath; | ||
| } | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.