mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #695 from Flow-Launcher/BrowserBookmarkRefactor
Refactor Bookmark plugin
This commit is contained in:
commit
8a33bf4a33
22 changed files with 455 additions and 313 deletions
|
|
@ -1,56 +0,0 @@
|
|||
using BinaryAnalysis.UnidecodeSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class Bookmark : IEquatable<Bookmark>, IEqualityComparer<Bookmark>
|
||||
{
|
||||
private string m_Name;
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_Name = value;
|
||||
}
|
||||
}
|
||||
public string Url { get; set; }
|
||||
public string Source { get; set; }
|
||||
public int Score { get; set; }
|
||||
|
||||
/* TODO: since Source maybe unimportant, we just need to compare Name and Url */
|
||||
public bool Equals(Bookmark other)
|
||||
{
|
||||
return Equals(this, other);
|
||||
}
|
||||
|
||||
public bool Equals(Bookmark x, Bookmark y)
|
||||
{
|
||||
if (Object.ReferenceEquals(x, y)) return true;
|
||||
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
|
||||
return false;
|
||||
|
||||
return x.Name == y.Name && x.Url == y.Url;
|
||||
}
|
||||
|
||||
public int GetHashCode(Bookmark bookmark)
|
||||
{
|
||||
if (Object.ReferenceEquals(bookmark, null)) return 0;
|
||||
int hashName = bookmark.Name == null ? 0 : bookmark.Name.GetHashCode();
|
||||
int hashUrl = bookmark.Url == null ? 0 : bookmark.Url.GetHashCode();
|
||||
return hashName ^ hashUrl;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return GetHashCode(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class ChromeBookmarkLoader : ChromiumBookmarkLoader
|
||||
{
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
{
|
||||
return LoadChromeBookmarks();
|
||||
}
|
||||
|
||||
private List<Bookmark> LoadChromeBookmarks()
|
||||
{
|
||||
var bookmarks = new List<Bookmark>();
|
||||
String platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome\User Data"), "Google Chrome"));
|
||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome SxS\User Data"), "Google Chrome Canary"));
|
||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Chromium\User Data"), "Chromium"));
|
||||
return bookmarks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class ChromeBookmarks
|
||||
{
|
||||
private List<Bookmark> bookmarks = new List<Bookmark>();
|
||||
|
||||
public List<Bookmark> GetBookmarks()
|
||||
{
|
||||
bookmarks.Clear();
|
||||
LoadChromeBookmarks();
|
||||
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
private void ParseChromeBookmarks(String path, string source)
|
||||
{
|
||||
if (!File.Exists(path)) return;
|
||||
|
||||
string all = File.ReadAllText(path);
|
||||
Regex nameRegex = new Regex("\"name\": \"(?<name>.*?)\"");
|
||||
MatchCollection nameCollection = nameRegex.Matches(all);
|
||||
Regex typeRegex = new Regex("\"type\": \"(?<type>.*?)\"");
|
||||
MatchCollection typeCollection = typeRegex.Matches(all);
|
||||
Regex urlRegex = new Regex("\"url\": \"(?<url>.*?)\"");
|
||||
MatchCollection urlCollection = urlRegex.Matches(all);
|
||||
|
||||
List<string> names = (from Match match in nameCollection select match.Groups["name"].Value).ToList();
|
||||
List<string> types = (from Match match in typeCollection select match.Groups["type"].Value).ToList();
|
||||
List<string> urls = (from Match match in urlCollection select match.Groups["url"].Value).ToList();
|
||||
|
||||
int urlIndex = 0;
|
||||
for (int i = 0; i < names.Count; i++)
|
||||
{
|
||||
string name = DecodeUnicode(names[i]);
|
||||
string type = types[i];
|
||||
if (type == "url")
|
||||
{
|
||||
string url = urls[urlIndex];
|
||||
urlIndex++;
|
||||
|
||||
if (url == null) continue;
|
||||
if (url.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
if (url.StartsWith("vbscript:", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
|
||||
bookmarks.Add(new Bookmark()
|
||||
{
|
||||
Name = name,
|
||||
Url = url,
|
||||
Source = source
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadChromeBookmarks(string path, string name)
|
||||
{
|
||||
if (!Directory.Exists(path)) return;
|
||||
var paths = Directory.GetDirectories(path);
|
||||
|
||||
foreach (var profile in paths)
|
||||
{
|
||||
if (File.Exists(Path.Combine(profile, "Bookmarks")))
|
||||
ParseChromeBookmarks(Path.Combine(profile, "Bookmarks"), name + (Path.GetFileName(profile) == "Default" ? "" : (" (" + Path.GetFileName(profile) + ")")));
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadChromeBookmarks()
|
||||
{
|
||||
String platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
LoadChromeBookmarks(Path.Combine(platformPath, @"Google\Chrome\User Data"), "Google Chrome");
|
||||
LoadChromeBookmarks(Path.Combine(platformPath, @"Google\Chrome SxS\User Data"), "Google Chrome Canary");
|
||||
LoadChromeBookmarks(Path.Combine(platformPath, @"Chromium\User Data"), "Chromium");
|
||||
}
|
||||
|
||||
private String DecodeUnicode(String dataStr)
|
||||
{
|
||||
Regex reg = new Regex(@"(?i)\\[uU]([0-9a-f]{4})");
|
||||
return reg.Replace(dataStr, m => ((char)Convert.ToInt32(m.Groups[1].Value, 16)).ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public abstract class ChromiumBookmarkLoader : IBookmarkLoader
|
||||
{
|
||||
public abstract List<Bookmark> GetBookmarks();
|
||||
protected List<Bookmark> LoadBookmarks(string browserDataPath, string name)
|
||||
{
|
||||
var bookmarks = new List<Bookmark>();
|
||||
if (!Directory.Exists(browserDataPath)) return bookmarks;
|
||||
var paths = Directory.GetDirectories(browserDataPath);
|
||||
|
||||
foreach (var profile in paths)
|
||||
{
|
||||
var bookmarkPath = Path.Combine(profile, "Bookmarks");
|
||||
if (!File.Exists(bookmarkPath))
|
||||
continue;
|
||||
|
||||
var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})");
|
||||
bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source));
|
||||
}
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
protected List<Bookmark> LoadBookmarksFromFile(string path, string source)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return new();
|
||||
var bookmarks = new List<Bookmark>();
|
||||
using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path));
|
||||
if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement))
|
||||
return new();
|
||||
foreach (var folder in rootElement.EnumerateObject())
|
||||
{
|
||||
EnumerateFolderBookmark(folder.Value, bookmarks, source);
|
||||
}
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
private void EnumerateFolderBookmark(JsonElement folderElement, List<Bookmark> bookmarks, string source)
|
||||
{
|
||||
foreach (var subElement in folderElement.GetProperty("children").EnumerateArray())
|
||||
{
|
||||
switch (subElement.GetProperty("type").GetString())
|
||||
{
|
||||
case "folder":
|
||||
EnumerateFolderBookmark(subElement, bookmarks, source);
|
||||
break;
|
||||
default:
|
||||
bookmarks.Add(new Bookmark(
|
||||
subElement.GetProperty("name").GetString(),
|
||||
subElement.GetProperty("url").GetString(),
|
||||
source));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using Flow.Launcher.Plugin.SharedModels;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Commands
|
||||
{
|
||||
internal static class BookmarkLoader
|
||||
{
|
||||
internal static MatchResult MatchProgram(Bookmark bookmark, string queryString)
|
||||
{
|
||||
var match = StringMatcher.FuzzySearch(queryString, bookmark.Name);
|
||||
if (match.IsSearchPrecisionScoreMet())
|
||||
return match;
|
||||
|
||||
return StringMatcher.FuzzySearch(queryString, bookmark.Url);
|
||||
}
|
||||
|
||||
internal static List<Bookmark> LoadAllBookmarks(Settings setting)
|
||||
{
|
||||
|
||||
var chromeBookmarks = new ChromeBookmarkLoader();
|
||||
var mozBookmarks = new FirefoxBookmarkLoader();
|
||||
var edgeBookmarks = new EdgeBookmarkLoader();
|
||||
|
||||
var allBookmarks = new List<Bookmark>();
|
||||
|
||||
// Add Firefox bookmarks
|
||||
allBookmarks.AddRange(mozBookmarks.GetBookmarks());
|
||||
|
||||
// Add Chrome bookmarks
|
||||
allBookmarks.AddRange(chromeBookmarks.GetBookmarks());
|
||||
|
||||
// Add Edge (Chromium) bookmarks
|
||||
allBookmarks.AddRange(edgeBookmarks.GetBookmarks());
|
||||
|
||||
foreach (var browser in setting.CustomChromiumBrowsers)
|
||||
{
|
||||
var loader = new CustomChromiumBookmarkLoader(browser);
|
||||
allBookmarks.AddRange(loader.GetBookmarks());
|
||||
}
|
||||
|
||||
return allBookmarks.Distinct().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Plugin.SharedModels;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Commands
|
||||
{
|
||||
internal static class Bookmarks
|
||||
{
|
||||
internal static MatchResult MatchProgram(Bookmark bookmark, string queryString)
|
||||
{
|
||||
var match = StringMatcher.FuzzySearch(queryString, bookmark.Name);
|
||||
if (match.IsSearchPrecisionScoreMet())
|
||||
return match;
|
||||
|
||||
return StringMatcher.FuzzySearch(queryString, bookmark.Url);
|
||||
}
|
||||
|
||||
internal static List<Bookmark> LoadAllBookmarks()
|
||||
{
|
||||
var allbookmarks = new List<Bookmark>();
|
||||
|
||||
var chromeBookmarks = new ChromeBookmarks();
|
||||
var mozBookmarks = new FirefoxBookmarks();
|
||||
var edgeBookmarks = new EdgeBookmarks();
|
||||
|
||||
//TODO: Let the user select which browser's bookmarks are displayed
|
||||
// Add Firefox bookmarks
|
||||
mozBookmarks.GetBookmarks().ForEach(x => allbookmarks.Add(x));
|
||||
|
||||
// Add Chrome bookmarks
|
||||
chromeBookmarks.GetBookmarks().ForEach(x => allbookmarks.Add(x));
|
||||
|
||||
// Add Edge (Chromium) bookmarks
|
||||
edgeBookmarks.GetBookmarks().ForEach(x => allbookmarks.Add(x));
|
||||
|
||||
return allbookmarks.Distinct().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class CustomChromiumBookmarkLoader : ChromiumBookmarkLoader
|
||||
{
|
||||
public CustomChromiumBookmarkLoader(CustomBrowser browser)
|
||||
{
|
||||
BrowserName = browser.Name;
|
||||
BrowserDataPath = browser.DataDirectoryPath;
|
||||
}
|
||||
public string BrowserDataPath { get; init; }
|
||||
public string BookmarkFilePath { get; init; }
|
||||
public string BrowserName { get; init; }
|
||||
|
||||
public override List<Bookmark> GetBookmarks() => BrowserDataPath != null ? LoadBookmarks(BrowserDataPath, BrowserName) : LoadBookmarksFromFile(BookmarkFilePath, BrowserName);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class EdgeBookmarkLoader : ChromiumBookmarkLoader
|
||||
{
|
||||
|
||||
private readonly List<Bookmark> _bookmarks = new();
|
||||
|
||||
private void LoadEdgeBookmarks()
|
||||
{
|
||||
var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge\User Data"), "Microsoft Edge");
|
||||
LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge Dev\User Data"), "Microsoft Edge Dev");
|
||||
LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge SxS\User Data"), "Microsoft Edge Canary");
|
||||
}
|
||||
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
{
|
||||
_bookmarks.Clear();
|
||||
LoadEdgeBookmarks();
|
||||
return _bookmarks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class EdgeBookmarks
|
||||
{
|
||||
private List<Bookmark> bookmarks = new List<Bookmark>();
|
||||
|
||||
public List<Bookmark> GetBookmarks()
|
||||
{
|
||||
bookmarks.Clear();
|
||||
LoadEdgeBookmarks();
|
||||
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
private void ParseEdgeBookmarks(string path, string source)
|
||||
{
|
||||
if (!File.Exists(path)) return;
|
||||
|
||||
string all = File.ReadAllText(path);
|
||||
Regex nameRegex = new Regex("\"name\": \"(?<name>.*?)\"");
|
||||
MatchCollection nameCollection = nameRegex.Matches(all);
|
||||
Regex typeRegex = new Regex("\"type\": \"(?<type>.*?)\"");
|
||||
MatchCollection typeCollection = typeRegex.Matches(all);
|
||||
Regex urlRegex = new Regex("\"url\": \"(?<url>.*?)\"");
|
||||
MatchCollection urlCollection = urlRegex.Matches(all);
|
||||
|
||||
List<string> names = (from Match match in nameCollection select match.Groups["name"].Value).ToList();
|
||||
List<string> types = (from Match match in typeCollection select match.Groups["type"].Value).ToList();
|
||||
List<string> urls = (from Match match in urlCollection select match.Groups["url"].Value).ToList();
|
||||
|
||||
int urlIndex = 0;
|
||||
for (int i = 0; i < names.Count; i++)
|
||||
{
|
||||
string name = DecodeUnicode(names[i]);
|
||||
string type = types[i];
|
||||
if (type == "url")
|
||||
{
|
||||
string url = urls[urlIndex];
|
||||
urlIndex++;
|
||||
|
||||
if (url == null) continue;
|
||||
if (url.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
if (url.StartsWith("vbscript:", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
|
||||
bookmarks.Add(new Bookmark()
|
||||
{
|
||||
Name = name,
|
||||
Url = url,
|
||||
Source = source
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadEdgeBookmarks(string path, string name)
|
||||
{
|
||||
if (!Directory.Exists(path)) return;
|
||||
var paths = Directory.GetDirectories(path);
|
||||
|
||||
foreach (var profile in paths)
|
||||
{
|
||||
if (File.Exists(Path.Combine(profile, "Bookmarks")))
|
||||
ParseEdgeBookmarks(Path.Combine(profile, "Bookmarks"), name + (Path.GetFileName(profile) == "Default" ? "" : (" (" + Path.GetFileName(profile) + ")")));
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadEdgeBookmarks()
|
||||
{
|
||||
string platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
LoadEdgeBookmarks(Path.Combine(platformPath, @"Microsoft\Edge\User Data"), "Microsoft Edge");
|
||||
LoadEdgeBookmarks(Path.Combine(platformPath, @"Microsoft\Edge Dev\User Data"), "Microsoft Edge Dev");
|
||||
LoadEdgeBookmarks(Path.Combine(platformPath, @"Microsoft\Edge SxS\User Data"), "Microsoft Edge Canary");
|
||||
}
|
||||
|
||||
private string DecodeUnicode(string dataStr)
|
||||
{
|
||||
Regex reg = new Regex(@"(?i)\\[uU]([0-9a-f]{4})");
|
||||
return reg.Replace(dataStr, m => ((char)Convert.ToInt32(m.Groups[1].Value, 16)).ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SQLite;
|
||||
|
|
@ -6,7 +7,7 @@ using System.Linq;
|
|||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class FirefoxBookmarks
|
||||
public class FirefoxBookmarkLoader : IBookmarkLoader
|
||||
{
|
||||
private const string queryAllBookmarks = @"SELECT moz_places.url, moz_bookmarks.title
|
||||
FROM moz_places
|
||||
|
|
@ -27,10 +28,10 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
if (string.IsNullOrEmpty(PlacesPath) || !File.Exists(PlacesPath))
|
||||
return new List<Bookmark>();
|
||||
|
||||
var bookmarList = new List<Bookmark>();
|
||||
var bookmarkList = new List<Bookmark>();
|
||||
|
||||
// create the connection string and init the connection
|
||||
string dbPath = string.Format(dbPathFormat, PlacesPath);
|
||||
string dbPath = string.Format(dbPathFormat, PlacesPath);
|
||||
using (var dbConnection = new SQLiteConnection(dbPath))
|
||||
{
|
||||
// Open connection to the database file and execute the query
|
||||
|
|
@ -38,14 +39,13 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
var reader = new SQLiteCommand(queryAllBookmarks, dbConnection).ExecuteReader();
|
||||
|
||||
// return results in List<Bookmark> format
|
||||
bookmarList = reader.Select(x => new Bookmark()
|
||||
{
|
||||
Name = (x["title"] is DBNull) ? string.Empty : x["title"].ToString(),
|
||||
Url = x["url"].ToString()
|
||||
}).ToList();
|
||||
bookmarkList = reader.Select(
|
||||
x => new Bookmark(x["title"] is DBNull ? string.Empty : x["title"].ToString(),
|
||||
x["url"].ToString())
|
||||
).ToList();
|
||||
}
|
||||
|
||||
return bookmarList;
|
||||
return bookmarkList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -63,7 +63,8 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
|
||||
// get firefox default profile directory from profiles.ini
|
||||
string ini;
|
||||
using (var sReader = new StreamReader(profileIni)) {
|
||||
using (var sReader = new StreamReader(profileIni))
|
||||
{
|
||||
ini = sReader.ReadToEnd();
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +96,10 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
Version=2
|
||||
*/
|
||||
|
||||
var lines = ini.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList();
|
||||
var lines = ini.Split(new string[]
|
||||
{
|
||||
"\r\n"
|
||||
}, StringSplitOptions.None).ToList();
|
||||
|
||||
var defaultProfileFolderNameRaw = lines.Where(x => x.Contains("Default=") && x != "Default=1").FirstOrDefault() ?? string.Empty;
|
||||
|
||||
|
|
@ -104,14 +108,14 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
|
||||
var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last();
|
||||
|
||||
var indexOfDefaultProfileAtttributePath = lines.IndexOf("Path="+ defaultProfileFolderName);
|
||||
var indexOfDefaultProfileAtttributePath = lines.IndexOf("Path=" + defaultProfileFolderName);
|
||||
|
||||
// Seen in the example above, the IsRelative attribute is always above the Path attribute
|
||||
var relativeAttribute = lines[indexOfDefaultProfileAtttributePath - 1];
|
||||
|
||||
return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0
|
||||
? defaultProfileFolderName + @"\places.sqlite"
|
||||
: Path.Combine(profileFolderPath, defaultProfileFolderName) + @"\places.sqlite";
|
||||
? defaultProfileFolderName + @"\places.sqlite"
|
||||
: Path.Combine(profileFolderPath, defaultProfileFolderName) + @"\places.sqlite";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -126,4 +130,4 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -69,4 +69,8 @@
|
|||
<PackageReference Include="UnidecodeSharp" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Bookmark.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public interface IBookmarkLoader
|
||||
{
|
||||
public List<Bookmark> GetBookmarks();
|
||||
}
|
||||
}
|
||||
|
|
@ -14,4 +14,9 @@
|
|||
<system:String x:Key="flowlauncher_plugin_browserbookmark_settings_choose">Choose</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_copyurl_title">Copy url</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_copyurl_subtitle">Copy the bookmark's url to clipboard</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_loadBrowserFrom">Load Browser From:</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_browserName">Browser Name</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_browserBookmarkDataDirectory">DataDirectoryPath</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_addBrowserBookmark">Add Custom Browser Bookmark</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_removeBrowserBookmark">Delete Custom Browser Bookmark</system:String>
|
||||
</ResourceDictionary>
|
||||
|
|
@ -26,7 +26,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
|
||||
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
||||
|
||||
cachedBookmarks = Bookmarks.LoadAllBookmarks();
|
||||
cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings);
|
||||
}
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
|
|
@ -45,7 +45,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
Title = c.Name,
|
||||
SubTitle = c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
Score = Bookmarks.MatchProgram(c, param).Score,
|
||||
Score = BookmarkLoader.MatchProgram(c, param).Score,
|
||||
Action = _ =>
|
||||
{
|
||||
if (_settings.OpenInNewBrowserWindow)
|
||||
|
|
@ -93,7 +93,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
{
|
||||
cachedBookmarks.Clear();
|
||||
|
||||
cachedBookmarks = Bookmarks.LoadAllBookmarks();
|
||||
cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings);
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginTitle()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
|
||||
{
|
||||
// Source may be important in the future
|
||||
public record Bookmark(string Name, string Url, string Source = "")
|
||||
{
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hashName = Name?.GetHashCode() ?? 0;
|
||||
var hashUrl = Url?.GetHashCode() ?? 0;
|
||||
return hashName ^ hashUrl;
|
||||
}
|
||||
|
||||
public virtual bool Equals(Bookmark other)
|
||||
{
|
||||
return other != null && Name == other.Name && Url == other.Url;
|
||||
}
|
||||
|
||||
public List<CustomBrowser> CustomBrowsers { get; set; }= new();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
|
||||
{
|
||||
public class CustomBrowser : BaseModel
|
||||
{
|
||||
private string _name;
|
||||
private string _dataDirectoryPath;
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(nameof(Name));
|
||||
}
|
||||
}
|
||||
public string DataDirectoryPath
|
||||
{
|
||||
get => _dataDirectoryPath;
|
||||
set
|
||||
{
|
||||
_dataDirectoryPath = value;
|
||||
OnPropertyChanged(nameof(DataDirectoryPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,15 @@
|
|||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
|
||||
{
|
||||
public class Settings : BaseModel
|
||||
{
|
||||
public bool OpenInNewBrowserWindow { get; set; } = true;
|
||||
|
||||
public string BrowserPath { get; set; }
|
||||
|
||||
public ObservableCollection<CustomBrowser> CustomChromiumBrowsers { get; set; } = new();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<Window x:Class="Flow.Launcher.Plugin.BrowserBookmark.Views.CustomBrowserSettingWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Flow.Launcher.Plugin.BrowserBookmark.Models"
|
||||
mc:Ignorable="d"
|
||||
Title="CustomBrowserSetting" Height="450" Width="600"
|
||||
KeyDown="WindowKeyDown"
|
||||
>
|
||||
<Window.DataContext>
|
||||
<local:CustomBrowser/>
|
||||
</Window.DataContext>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="4*"/>
|
||||
<ColumnDefinition Width="6*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="Browser Name" FontSize="15"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Browser Data Directory Path" FontSize="15"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Name}"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center" Width="100" Height="30"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding DataDirectoryPath}"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center" Width="200" Height="30"/>
|
||||
<StackPanel HorizontalAlignment="Right" Grid.Row="2" Orientation="Horizontal" Grid.Column="1" Height="60">
|
||||
<Button Content="Confirm" Margin="15" Click="ConfirmEditCustomBrowser"/>
|
||||
<Button Content="Cancel" Margin="15"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for CustomBrowserSetting.xaml
|
||||
/// </summary>
|
||||
public partial class CustomBrowserSettingWindow : Window
|
||||
{
|
||||
private CustomBrowser currentCustomBrowser;
|
||||
public CustomBrowserSettingWindow(CustomBrowser browser)
|
||||
{
|
||||
InitializeComponent();
|
||||
currentCustomBrowser = browser;
|
||||
DataContext = new CustomBrowser
|
||||
{
|
||||
Name = browser.Name, DataDirectoryPath = browser.DataDirectoryPath
|
||||
};
|
||||
}
|
||||
|
||||
private void ConfirmEditCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is CustomBrowser editedBrowser)
|
||||
{
|
||||
currentCustomBrowser.Name = editedBrowser.Name;
|
||||
currentCustomBrowser.DataDirectoryPath = editedBrowser.DataDirectoryPath;
|
||||
}
|
||||
Close();
|
||||
}
|
||||
private void WindowKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
ConfirmEditCustomBrowser(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,21 +5,23 @@
|
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
Background="White"
|
||||
d:DesignHeight="300" d:DesignWidth="500">
|
||||
<Grid>
|
||||
d:DesignHeight="300" d:DesignWidth="500"
|
||||
DataContext="{Binding RelativeSource={RelativeSource Self}}">
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="90" />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="50" />
|
||||
<RowDefinition Height="80"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel>
|
||||
<Grid Grid.Row="0" Margin="40 40 0 0">
|
||||
<Grid Grid.Row="0" Margin="30 20 0 0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="160" />
|
||||
<ColumnDefinition Width="140"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0" Content="{DynamicResource flowlauncher_plugin_browserbookmark_settings_openBookmarks}"
|
||||
FontSize="15" Margin="0 5 0 0"/>
|
||||
FontSize="15" Margin="10 5 0 0"/>
|
||||
<RadioButton Grid.Column="1" Name="NewWindowBrowser" GroupName="OpenSearchBehaviour"
|
||||
Content="{DynamicResource flowlauncher_plugin_browserbookmark_settings_newWindow}"
|
||||
Click="OnNewBrowserWindowClick" />
|
||||
|
|
@ -28,12 +30,42 @@
|
|||
Click="OnNewTabClick" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<StackPanel VerticalAlignment="Top" Grid.Row="1" Height="106" Margin="41,13,0,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" Grid.Row="1" Height="60" Margin="30,20,0,0">
|
||||
<Label Content="{DynamicResource flowlauncher_plugin_browserbookmark_settings_setBrowserFromPath}"
|
||||
Height="28" Margin="0,0,155,0" HorizontalAlignment="Left" Width="290"/>
|
||||
<TextBox x:Name="browserPathBox" HorizontalAlignment="Left" Height="34" TextWrapping="NoWrap" VerticalAlignment="Top" Width="311" RenderTransformOrigin="0.502,-1.668" TextChanged="OnBrowserPathTextChanged" />
|
||||
<Button x:Name="viewButton" Content="{DynamicResource flowlauncher_plugin_browserbookmark_settings_choose}"
|
||||
HorizontalAlignment="Left" Margin="340,-35,-1,0" Width="100" Height="34" Click="OnChooseClick" FontSize="14" />
|
||||
Height="28" Margin="10"/>
|
||||
<TextBox x:Name="BrowserPathBox"
|
||||
HorizontalAlignment="Left"
|
||||
Height="30"
|
||||
TextWrapping="NoWrap"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Settings.BrowserPath}"
|
||||
Width="240"
|
||||
Margin="10"/>
|
||||
<Button x:Name="ViewButton" Content="{DynamicResource flowlauncher_plugin_browserbookmark_settings_choose}"
|
||||
HorizontalAlignment="Left" Margin="10" Width="100" Height="30" Click="OnChooseClick" FontSize="14" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="2" Orientation="Vertical" Margin="30,20,0,0">
|
||||
<TextBlock Text="{DynamicResource flowlauncher_plugin_browserbookmark_loadBrowserFrom}" Margin="10"/>
|
||||
<ListView Grid.Row="2" ItemsSource="{Binding Settings.CustomChromiumBrowsers}"
|
||||
SelectedItem="{Binding SelectedCustomBrowser}"
|
||||
Margin="10"
|
||||
BorderBrush="DarkGray"
|
||||
BorderThickness="1"
|
||||
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}"
|
||||
Height="auto"
|
||||
Name="CustomBrowsers"
|
||||
MouseDoubleClick="MouseDoubleClickOnSelectedCustomBrowser">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn DisplayMemberBinding="{Binding Name, Mode=OneWay}" Header="{DynamicResource flowlauncher_plugin_browserbookmark_browserName}"/>
|
||||
<GridViewColumn DisplayMemberBinding="{Binding DataDirectoryPath, Mode=OneWay}" Header="{DynamicResource flowlauncher_plugin_browserbookmark_browserBookmarkDataDirectory}"/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<Button Content="{DynamicResource flowlauncher_plugin_browserbookmark_addBrowserBookmark}" Margin="10" Click="NewCustomBrowser"/>
|
||||
<Button Content="{DynamicResource flowlauncher_plugin_browserbookmark_removeBrowserBookmark}" Margin="10" Click="DeleteCustomBrowser"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
@ -2,33 +2,34 @@ using Microsoft.Win32;
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for BrowserBookmark.xaml
|
||||
/// </summary>
|
||||
public partial class SettingsControl : UserControl
|
||||
public partial class SettingsControl
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
public Settings Settings { get; }
|
||||
public CustomBrowser SelectedCustomBrowser { get; set; }
|
||||
|
||||
public SettingsControl(Settings settings)
|
||||
{
|
||||
Settings = settings;
|
||||
InitializeComponent();
|
||||
_settings = settings;
|
||||
browserPathBox.Text = _settings.BrowserPath;
|
||||
NewWindowBrowser.IsChecked = _settings.OpenInNewBrowserWindow;
|
||||
NewTabInBrowser.IsChecked = !_settings.OpenInNewBrowserWindow;
|
||||
NewWindowBrowser.IsChecked = Settings.OpenInNewBrowserWindow;
|
||||
NewTabInBrowser.IsChecked = !Settings.OpenInNewBrowserWindow;
|
||||
}
|
||||
|
||||
private void OnNewBrowserWindowClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_settings.OpenInNewBrowserWindow = true;
|
||||
Settings.OpenInNewBrowserWindow = true;
|
||||
}
|
||||
|
||||
private void OnNewTabClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_settings.OpenInNewBrowserWindow = false;
|
||||
Settings.OpenInNewBrowserWindow = false;
|
||||
}
|
||||
|
||||
private void OnChooseClick(object sender, RoutedEventArgs e)
|
||||
|
|
@ -39,14 +40,39 @@ namespace Flow.Launcher.Plugin.BrowserBookmark.Views
|
|||
fileBrowserDialog.CheckPathExists = true;
|
||||
if (fileBrowserDialog.ShowDialog() == true)
|
||||
{
|
||||
browserPathBox.Text = fileBrowserDialog.FileName;
|
||||
_settings.BrowserPath = fileBrowserDialog.FileName;
|
||||
Settings.BrowserPath = fileBrowserDialog.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBrowserPathTextChanged(object sender, TextChangedEventArgs e)
|
||||
private void NewCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_settings.BrowserPath = browserPathBox.Text;
|
||||
var newBrowser = new CustomBrowser();
|
||||
var window = new CustomBrowserSettingWindow(newBrowser);
|
||||
window.ShowDialog();
|
||||
if (newBrowser is not
|
||||
{
|
||||
Name: null,
|
||||
DataDirectoryPath: null
|
||||
})
|
||||
{
|
||||
Settings.CustomChromiumBrowsers.Add(newBrowser);
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteCustomBrowser(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(CustomBrowsers.SelectedItem is CustomBrowser selectedCustomBrowser)
|
||||
{
|
||||
Settings.CustomChromiumBrowsers.Remove(selectedCustomBrowser);
|
||||
}
|
||||
}
|
||||
private void MouseDoubleClickOnSelectedCustomBrowser(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (SelectedCustomBrowser is null)
|
||||
return;
|
||||
|
||||
var window = new CustomBrowserSettingWindow(SelectedCustomBrowser);
|
||||
window.ShowDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "Browser Bookmarks",
|
||||
"Description": "Search your browser bookmarks",
|
||||
"Author": "qianlifeng, Ioannis G.",
|
||||
"Version": "1.4.4",
|
||||
"Version": "1.5.0",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.BrowserBookmark.dll",
|
||||
|
|
|
|||
Loading…
Reference in a new issue