Merge lp:~michaelaquilina/synapse-project/chrome-bookmarks-plugin into lp:synapse-project

Proposed by Michael Aquilina on 2016-02-22
Status: Needs review
Proposed branch: lp:~michaelaquilina/synapse-project/chrome-bookmarks-plugin
Merge into: lp:synapse-project
Diff against target: 251 lines (+220/-1)
3 files modified
src/plugins/Makefile.am (+1/-1)
src/plugins/chrome-bookmarks-plugin.vala (+218/-0)
src/ui/synapse-main.vala (+1/-0)
To merge this branch: bzr merge lp:~michaelaquilina/synapse-project/chrome-bookmarks-plugin
Reviewer Review Type Date Requested Status
Synapse core team 2016-02-22 Pending
Review via email: mp+286756@code.launchpad.net

Description of the change

Based on the existing chromium plugin. Enables searching for chrome bookmarks.

I would be happy to change it so that the chromium plugin simply also searches in the chrome directory if you feel that's better.

To post a comment you must log in.

Unmerged revisions

637. By Michael Aquilina on 2016-02-21

Add Chrome bookmarks plugin

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/plugins/Makefile.am'
2--- src/plugins/Makefile.am 2015-07-21 08:13:23 +0000
3+++ src/plugins/Makefile.am 2016-02-22 00:38:39 +0000
4@@ -30,6 +30,7 @@
5 calculator-plugin.vala \
6 chat-actions-plugin.vala \
7 chromium-plugin.vala \
8+ chrome-bookmarks-plugin.vala \
9 command-plugin.vala \
10 file-op-plugin.vala \
11 desktop-file-plugin.vala \
12@@ -94,4 +95,3 @@
13 plugins.vapi \
14 plugins.h \
15 $(NULL)
16-
17
18=== added file 'src/plugins/chrome-bookmarks-plugin.vala'
19--- src/plugins/chrome-bookmarks-plugin.vala 1970-01-01 00:00:00 +0000
20+++ src/plugins/chrome-bookmarks-plugin.vala 2016-02-22 00:38:39 +0000
21@@ -0,0 +1,218 @@
22+/*
23+ * Copyright (C) 2013 Jan Hrdina <jan.hrdka@gmail.com>
24+ *
25+ * This program is free software: you can redistribute it and/or modify it
26+ * under the terms of the GNU General Public License as published by the
27+ * Free Software Foundation, either version 3 of the License, or
28+ * (at your option) any later version.
29+ *
30+ * This program is distributed in the hope that it will be useful, but
31+ * WITHOUT ANY WARRANTY; without even the implied warranty of
32+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
33+ * See the GNU General Public License for more details.
34+ *
35+ * You should have received a copy of the GNU General Public License along
36+ * with this program. If not, see <http://www.gnu.org/licenses/>.
37+ */
38+
39+namespace Synapse
40+{
41+
42+ public class ChromeBookmarksPlugin : Object, Activatable, ItemProvider
43+ {
44+ public bool enabled { get; set; default = true; }
45+
46+ public void activate ()
47+ {
48+
49+ }
50+
51+ public void deactivate ()
52+ {
53+
54+ }
55+
56+ private class BookmarkMatch : UriMatch
57+ {
58+ private string? title_folded = null;
59+ private string? uri_folded = null;
60+
61+ public unowned string get_title_folded ()
62+ {
63+ if (title_folded == null) title_folded = title.casefold ();
64+ return title_folded;
65+ }
66+
67+ public unowned string get_uri_folded ()
68+ {
69+ if (uri_folded == null) uri_folded = uri.casefold ();
70+ return uri_folded;
71+ }
72+
73+ public BookmarkMatch.with_content (string name, string url)
74+ {
75+ Object (title: name,
76+ description: url,
77+ uri: url,
78+ mime_type: "text/html",
79+ has_thumbnail: false, icon_name: "text-html");
80+ }
81+ }
82+
83+ static void register_plugin ()
84+ {
85+ PluginRegistry.get_default ().register_plugin (
86+ typeof (ChromeBookmarksPlugin),
87+ _("Chrome Bookmarks Plugin"),
88+ _("Browse and open Chrome bookmarks."),
89+ "google-chrome",
90+ register_plugin,
91+ Environment.find_program_in_path ("google-chrome") != null,
92+ _("Google Chrome is not installed")
93+ );
94+ }
95+
96+ static construct
97+ {
98+ register_plugin ();
99+ }
100+
101+ private Utils.AsyncOnce<Gee.List<BookmarkMatch>> bookmarks_once;
102+
103+ construct
104+ {
105+ bookmarks_once = new Utils.AsyncOnce<Gee.List<BookmarkMatch>> ();
106+ }
107+
108+ private void full_search (Query q, ResultSet results,
109+ MatcherFlags flags = 0)
110+ {
111+ // try to match against global matchers and if those fail, try also exec
112+ var matchers = Query.get_matchers_for_query (q.query_string_folded, flags);
113+
114+ foreach (var bmk in bookmarks_once.get_data())
115+ {
116+ unowned string name = bmk.get_title_folded ();
117+ unowned string url = bmk.get_uri_folded ();
118+
119+ foreach (var matcher in matchers)
120+ {
121+ if (matcher.key.match (name))
122+ {
123+ results.add (bmk, matcher.value);
124+ break;
125+ }
126+ if (url != null && matcher.key.match (url))
127+ {
128+ results.add (bmk, matcher.value);
129+ break;
130+ }
131+ }
132+ }
133+ }
134+
135+ public bool handles_query (Query query)
136+ {
137+ return (QueryFlags.INTERNET in query.query_type);
138+ }
139+
140+ public async ResultSet? search (Query q) throws SearchError
141+ {
142+ var result = new ResultSet ();
143+
144+ if (!bookmarks_once.is_initialized ())
145+ {
146+ yield parse_bookmarks ();
147+ }
148+
149+ if (q.query_string.char_count () == 1)
150+ {
151+ var flags = MatcherFlags.NO_SUBSTRING | MatcherFlags.NO_PARTIAL |
152+ MatcherFlags.NO_FUZZY;
153+ full_search (q, result, flags);
154+ }
155+ else
156+ {
157+ full_search (q, result);
158+ }
159+
160+ q.check_cancellable ();
161+
162+ return result;
163+ }
164+
165+
166+ /* Bookmarks parsing methods */
167+
168+ private static bool is_container (Json.Object o, string container_string)
169+ {
170+ return o.get_string_member ("type") == container_string;
171+ }
172+
173+ private static bool is_bookmark (Json.Object o)
174+ {
175+ return o.has_member ("url");
176+ }
177+
178+ private static bool is_good (Json.Object o, Gee.HashSet<string> unwanted_scheme)
179+ {
180+ return !unwanted_scheme.contains (o.get_string_member ("url")
181+ .split (":", 1)[0]);
182+ }
183+
184+ private async void parse_bookmarks ()
185+ {
186+ var is_locked = yield bookmarks_once.enter ();
187+ if (!is_locked) return;
188+
189+ var bookmarks = new Gee.ArrayList<BookmarkMatch> ();
190+ var parser = new Json.Parser ();
191+ string fpath = GLib.Path.build_filename (
192+ Environment.get_user_config_dir (), "google-chrome", "Default", "Bookmarks");
193+
194+ string CONTAINER = "folder";
195+ Gee.HashSet<string> UNWANTED_SCHEME = new Gee.HashSet<string> ();
196+ UNWANTED_SCHEME.add ("data");
197+ UNWANTED_SCHEME.add ("place");
198+ UNWANTED_SCHEME.add ("javascript");
199+
200+ List<unowned Json.Node> folders = new List<Json.Node> ();
201+
202+ try
203+ {
204+ File f = File.new_for_path (fpath);
205+ var input_stream = yield f.read_async (Priority.DEFAULT);
206+ yield parser.load_from_stream_async (input_stream);
207+
208+ var root_object = parser.get_root ().get_object ();
209+ folders.concat (root_object.get_member ("roots").get_object ()
210+ .get_member ("bookmark_bar").get_object ()
211+ .get_array_member ("children").get_elements ());
212+ folders.concat (root_object.get_member ("roots").get_object ()
213+ .get_member ("other").get_object ()
214+ .get_array_member ("children").get_elements ());
215+
216+ Json.Object o;
217+ foreach (var item in folders)
218+ {
219+ o = item.get_object ();
220+ if (is_bookmark (o) && is_good (o, UNWANTED_SCHEME))
221+ {
222+ bookmarks.add (new BookmarkMatch.with_content (
223+ o.get_string_member ("name"),
224+ o.get_string_member ("url")));
225+ }
226+ if (is_container (o, CONTAINER))
227+ {
228+ folders.concat(o.get_array_member ("children").get_elements ());
229+ }
230+ }
231+ }
232+ catch (Error err)
233+ {
234+ warning ("%s", err.message);
235+ }
236+ bookmarks_once.leave (bookmarks);
237+ }
238+ }
239+}
240
241=== modified file 'src/ui/synapse-main.vala'
242--- src/ui/synapse-main.vala 2015-10-05 07:03:23 +0000
243+++ src/ui/synapse-main.vala 2016-02-22 00:38:39 +0000
244@@ -176,6 +176,7 @@
245 typeof (SshPlugin),
246 typeof (XnoiseActions),
247 typeof (ChromiumPlugin),
248+ typeof (ChromeBookmarksPlugin),
249 typeof (FileOpPlugin),
250 typeof (PidginPlugin),
251 typeof (ChatActions),