[epiphany] Add Chrome/Chromium bookmark importer



commit 1b128214d310183e4443468ed3e92315fa810f64
Author: Jan-Michael Brummer <jan brummer tabos org>
Date:   Tue Apr 21 19:46:27 2020 +0200

    Add Chrome/Chromium bookmark importer
    
    Fixes: https://gitlab.gnome.org/GNOME/epiphany/-/issues/352

 src/bookmarks/ephy-bookmarks-import.c | 120 +++++++++++++++++++++++++++++
 src/bookmarks/ephy-bookmarks-import.h |   4 +
 src/window-commands.c                 | 138 ++++++++++++++++++++++++++++------
 3 files changed, 241 insertions(+), 21 deletions(-)
---
diff --git a/src/bookmarks/ephy-bookmarks-import.c b/src/bookmarks/ephy-bookmarks-import.c
index de80a907b..e80745001 100644
--- a/src/bookmarks/ephy-bookmarks-import.c
+++ b/src/bookmarks/ephy-bookmarks-import.c
@@ -520,3 +520,123 @@ ephy_bookmarks_import_from_html (EphyBookmarksManager  *manager,
   parser_data_free (data);
   return TRUE;
 }
+
+static void chrome_import_folder (JsonObject *object,
+                                  GSequence  *bookmarks);
+
+static void
+chrome_add_child (JsonArray *array,
+                  guint      index_,
+                  JsonNode  *element_node,
+                  gpointer   user_data)
+{
+  GSequence *bookmarks = user_data;
+  JsonObject *object = json_node_get_object (element_node);
+  const char *title;
+  const char *time;
+  const char *type;
+
+  if (!object)
+    return;
+
+  title = json_object_get_string_member (object, "name");
+  type = json_object_get_string_member (object, "type");
+  time = json_object_get_string_member (object, "date_added");
+
+  if (g_strcmp0 (type, "url") == 0) {
+    const char *url;
+
+    url = json_object_get_string_member (object, "url");
+
+    if (title && url && !g_str_has_prefix (url, "chrome://") && time) {
+      g_autofree const char *guid = ephy_bookmark_generate_random_id ();
+      EphyBookmark *bookmark;
+      GSequence *tags;
+      gint64 time_added;
+
+      tags = g_sequence_new (g_free);
+      time_added = g_ascii_strtoll (time, NULL, 0);
+
+      bookmark = ephy_bookmark_new (url, title, tags, guid);
+      ephy_bookmark_set_time_added (bookmark, time_added);
+      ephy_synchronizable_set_server_time_modified (EPHY_SYNCHRONIZABLE (bookmark), time_added);
+
+      g_sequence_prepend (bookmarks, bookmark);
+    }
+  } else if (g_strcmp0 (type, "folder") == 0) {
+    chrome_import_folder (object, bookmarks);
+  }
+}
+
+static void
+chrome_import_folder (JsonObject *object,
+                      GSequence  *bookmarks)
+{
+  JsonArray *children;
+  const char *type;
+
+  type = json_object_get_string_member (object, "type");
+  if (g_strcmp0 (type, "folder") != 0)
+    return;
+
+  children = json_object_get_array_member (object, "children");
+  if (children)
+    json_array_foreach_element (children, chrome_add_child, bookmarks);
+}
+
+static void
+chrome_parse_root (JsonObject  *object,
+                   const gchar *member_name,
+                   JsonNode    *member_node,
+                   gpointer     user_data)
+{
+  JsonObject *member_object;
+
+  member_object = json_node_get_object (member_node);
+  chrome_import_folder (member_object, user_data);
+}
+
+gboolean
+ephy_bookmarks_import_from_chrome (EphyBookmarksManager  *manager,
+                                   const char            *filename,
+                                   GError               **error)
+{
+  g_autoptr (GSequence) bookmarks = NULL;
+  g_autoptr (JsonParser) parser = NULL;
+  JsonNode *root;
+  JsonObject *object;
+  JsonObject *roots_object;
+
+  parser = json_parser_new ();
+
+  if (!json_parser_load_from_file (parser, filename, error))
+    return FALSE;
+
+  root = json_parser_get_root (parser);
+  if (!root)
+    goto parser_error;
+
+  object = json_node_get_object (root);
+  if (!object)
+    goto parser_error;
+
+  roots_object = json_object_get_object_member (object, "roots");
+  if (!roots_object)
+    goto parser_error;
+
+  bookmarks = g_sequence_new (g_object_unref);
+
+  json_object_foreach_member (roots_object, chrome_parse_root, bookmarks);
+
+  ephy_bookmarks_manager_add_bookmarks (manager, bookmarks);
+
+  return TRUE;
+
+parser_error:
+  g_set_error (error,
+               BOOKMARKS_IMPORT_ERROR,
+               BOOKMARKS_IMPORT_ERROR_BOOKMARKS,
+               _("Bookmarks file could not be parsed:"));
+
+  return FALSE;
+}
diff --git a/src/bookmarks/ephy-bookmarks-import.h b/src/bookmarks/ephy-bookmarks-import.h
index 972d70baf..33b804ad6 100644
--- a/src/bookmarks/ephy-bookmarks-import.h
+++ b/src/bookmarks/ephy-bookmarks-import.h
@@ -40,4 +40,8 @@ gboolean    ephy_bookmarks_import_from_html     (EphyBookmarksManager  *manager,
                                                  const char            *filename,
                                                  GError               **error);
 
+gboolean    ephy_bookmarks_import_from_chrome   (EphyBookmarksManager  *manager,
+                                                 const char            *filename,
+                                                 GError               **error);
+
 G_END_DECLS
diff --git a/src/window-commands.c b/src/window-commands.c
index 92c523b2d..072c81b6a 100644
--- a/src/window-commands.c
+++ b/src/window-commands.c
@@ -93,10 +93,28 @@ window_cmd_new_incognito_window (GSimpleAction *action,
   ephy_open_incognito_window (NULL);
 }
 
-const gchar *import_option_names[3] = {
-  N_("GVDB File"),
-  N_("HTML File"),
-  N_("Firefox")
+typedef enum {
+  IMPORT_TYPE_CHOOSE,
+  IMPORT_TYPE_IMPORT
+} ImportTypes;
+
+
+struct import_option {
+  const char *name;
+  ImportTypes type;
+  gboolean (*exists)(void);
+};
+
+static gboolean firefox_exists (void);
+static gboolean chrome_exists (void);
+static gboolean chromium_exists (void);
+
+static struct import_option import_options[] = {
+  { N_("GVDB File"), IMPORT_TYPE_CHOOSE, NULL },
+  { N_("HTML File"), IMPORT_TYPE_CHOOSE, NULL },
+  { N_("Firefox"), IMPORT_TYPE_IMPORT, firefox_exists },
+  { N_("Chrome"), IMPORT_TYPE_IMPORT, chrome_exists },
+  { N_("Chromium"), IMPORT_TYPE_IMPORT, chromium_exists }
 };
 
 static void
@@ -109,9 +127,9 @@ combo_box_changed_cb (GtkComboBox *combo_box,
   g_assert (GTK_IS_BUTTON (button));
 
   active = gtk_combo_box_get_active (combo_box);
-  if (active == 0 || active == 1)
+  if (import_options[active].type == IMPORT_TYPE_CHOOSE)
     gtk_button_set_label (button, _("Ch_oose File"));
-  else if (active == 2)
+  else if (import_options[active].type == IMPORT_TYPE_IMPORT)
     gtk_button_set_label (button, _("I_mport"));
 }
 
@@ -182,6 +200,39 @@ get_firefox_profiles (void)
   return profiles;
 }
 
+static gboolean
+firefox_exists (void)
+{
+  GSList *firefox_profiles;
+  gboolean has_firefox_profile;
+
+  firefox_profiles = get_firefox_profiles ();
+  has_firefox_profile = g_slist_length (firefox_profiles) > 0;
+  g_slist_free (firefox_profiles);
+
+  return has_firefox_profile;
+}
+
+static gboolean
+chrome_exists (void)
+{
+  g_autofree char *filename = NULL;
+
+  filename = g_build_filename (g_get_user_config_dir (), "google-chrome", "Default", "Bookmarks", NULL);
+
+  return g_file_test (filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR);
+}
+
+static gboolean
+chromium_exists (void)
+{
+  g_autofree char *filename = NULL;
+
+  filename = g_build_filename (g_get_user_config_dir (), "chromium", "Default", "Bookmarks", NULL);
+
+  return g_file_test (filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR);
+}
+
 static GtkTreeModel *
 create_tree_model (void)
 {
@@ -190,27 +241,16 @@ create_tree_model (void)
   };
   GtkListStore *list_store;
   GtkTreeIter iter;
-  GSList *firefox_profiles;
-  gboolean has_firefox_profile;
   int i;
 
-
-  /* Check if user has a firefox profile*/
-  firefox_profiles = get_firefox_profiles ();
-  has_firefox_profile = g_slist_length (firefox_profiles) > 0;
-  g_slist_free (firefox_profiles);
-
   list_store = gtk_list_store_new (1, G_TYPE_STRING);
-  for (i = G_N_ELEMENTS (import_option_names) - 1; i >= 0; i--) {
-    /* Skip Firefox option if user doesn't have a Firefox profile */
-    if (g_strcmp0 (import_option_names[i], _("Firefox")) == 0) {
-      if (!has_firefox_profile)
-        continue;
-    }
+  for (i = G_N_ELEMENTS (import_options) - 1; i >= 0; i--) {
+    if (import_options[i].exists && !import_options[i].exists ())
+      continue;
 
     gtk_list_store_prepend (list_store, &iter);
     gtk_list_store_set (list_store, &iter,
-                        TEXT_COL, _(import_option_names[i]),
+                        TEXT_COL, _(import_options[i].name),
                         -1);
   }
 
@@ -410,6 +450,56 @@ dialog_bookmarks_import_from_firefox (GtkDialog *dialog)
   return imported;
 }
 
+static gboolean
+dialog_bookmarks_import_from_chrome (GtkDialog *dialog)
+{
+  EphyBookmarksManager *manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
+  GtkWidget *import_info_dialog;
+  g_autoptr (GError) error = NULL;
+  g_autofree gchar *filename;
+  gboolean imported;
+
+  filename = g_build_filename (g_get_user_config_dir (), "google-chrome", "Default", "Bookmarks", NULL);
+
+  imported = ephy_bookmarks_import_from_chrome (manager, filename, &error);
+  import_info_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
+                                               GTK_DIALOG_MODAL,
+                                               imported ? GTK_MESSAGE_INFO : GTK_MESSAGE_WARNING,
+                                               GTK_BUTTONS_OK,
+                                               "%s",
+                                               imported ? _("Bookmarks successfully imported!")
+                                                        : error->message);
+  gtk_dialog_run (GTK_DIALOG (import_info_dialog));
+  gtk_widget_destroy (import_info_dialog);
+
+  return imported;
+}
+
+static gboolean
+dialog_bookmarks_import_from_chromium (GtkDialog *dialog)
+{
+  EphyBookmarksManager *manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
+  GtkWidget *import_info_dialog;
+  g_autoptr (GError) error = NULL;
+  g_autofree gchar *filename;
+  gboolean imported;
+
+  filename = g_build_filename (g_get_user_config_dir (), "chromium", "Default", "Bookmarks", NULL);
+
+  imported = ephy_bookmarks_import_from_chrome (manager, filename, &error);
+  import_info_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
+                                               GTK_DIALOG_MODAL,
+                                               imported ? GTK_MESSAGE_INFO : GTK_MESSAGE_WARNING,
+                                               GTK_BUTTONS_OK,
+                                               "%s",
+                                               imported ? _("Bookmarks successfully imported!")
+                                                        : error->message);
+  gtk_dialog_run (GTK_DIALOG (import_info_dialog));
+  gtk_widget_destroy (import_info_dialog);
+
+  return imported;
+}
+
 static void
 dialog_bookmarks_import_cb (GtkDialog   *dialog,
                             int          response,
@@ -430,6 +520,12 @@ dialog_bookmarks_import_cb (GtkDialog   *dialog,
       case 2:
         imported = dialog_bookmarks_import_from_firefox (dialog);
         break;
+      case 3:
+        imported = dialog_bookmarks_import_from_chrome (dialog);
+        break;
+      case 4:
+        imported = dialog_bookmarks_import_from_chromium (dialog);
+        break;
       default:
         g_assert_not_reached ();
     }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]