Skip to content

Commit

Permalink
Merge pull request #3077 from hgluka/import-history
Browse files Browse the repository at this point in the history
Import history from other browsers.
  • Loading branch information
jmercouris authored Aug 2, 2023
2 parents 2fcbdc3 + 20a3fda commit bbf8d8f
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -600,3 +600,7 @@
path = _build/cl-json
url = https://github.com/sharplispers/cl-json
shallow = true
[submodule "_build/cl-sqlite"]
path = _build/cl-sqlite
url = https://github.com/TeMPOraL/cl-sqlite
shallow = true
1 change: 1 addition & 0 deletions _build/cl-sqlite
Submodule cl-sqlite added at be2fcc
1 change: 1 addition & 0 deletions build-scripts/nyxt.scm
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@
cl-str
cl-slime-swank
cl-slynk
cl-sqlite
cl-tld
cl-trivia
cl-trivial-clipboard
Expand Down
1 change: 1 addition & 0 deletions documents/SOURCES.org
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Experimental support.
- cl-ppcre-unicode
- cl-prevalence
- cl-qrencode
- cl-sqlite
- cl-tld
- closer-mop
- cluffer
Expand Down
2 changes: 2 additions & 0 deletions nyxt.asd
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ The renderer is configured from NYXT_RENDERER or `*nyxt-renderer*'."))
clss
spinneret
slynk
sqlite
swank
trivia
trivial-clipboard
Expand Down Expand Up @@ -240,6 +241,7 @@ The renderer is configured from NYXT_RENDERER or `*nyxt-renderer*'."))
(:file "emacs")
(:file "expedition")
(:file "force-https")
(:file "history-migration")
(:file "macro-edit")
(:file "no-image")
(:file "no-procrastinate" :depends-on ("blocker"))
Expand Down
6 changes: 6 additions & 0 deletions source/changelog.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,12 @@ buffers.")
(:li "Fix styling of progress bar.")
(:li "Fix styling of prompt buffer's input area."))))

(define-version "3.X.Y"
(:ul
(:li "Add commands for importing history from other browsers.
Currently, the supported browsers are Firefox, Google Chrome,
Chromium, Brave and Vivaldi.")))

(define-version "4-pre-release-1"
(:li "When on pre-release, push " (:code "X-pre-release")
" feature in addition to " (:code "X-pre-release-N") "one."))
Expand Down
115 changes: 115 additions & 0 deletions source/mode/history-migration.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
;;;; SPDX-FileCopyrightText: Atlas Engineer LLC
;;;; SPDX-License-Identifier: BSD-3-Clause

(nyxt:define-package :nyxt/mode/history-migration
(:documentation "Package for `history-migration-mode', mode to import history from other
browsers."))
(in-package :nyxt/mode/history-migration)

(define-mode history-migration-mode ()
"Mode for importing history from other browsers."
((visible-in-status-p nil)
(rememberable-p nil))
(:toggler-command-p nil))

(define-class external-browser-history-source (prompter:source)
((prompter:name "History files")
(browser-lambda :accessor browser-lambda :initarg :browser-lambda)
(prompter:constructor
(lambda (source)
(echo "Searching for history file. This may take some time.")
(or (let ((results '()))
(uiop:collect-sub*directories
(user-homedir-pathname)
(constantly t)
(lambda (subdir)
(equal (iolib/os:file-kind subdir) :directory))
(lambda (subdir)
(let ((browser-history-file (funcall* (browser-lambda source) subdir)))
(when browser-history-file
(push browser-history-file results)))))
results)
(echo-warning "No history files found."))))))

(defmacro define-history-import-command (name docstring &key sql-query file-path)
"Shorthand to define a global command for importing history from a browser.
Make sure that the sql-query is a SELECT statement that selects:
- url
- title
- last-access (unix time in seconds)
- visits
Or the equivalent columns for the browser in question."
`(define-command-global ,name ()
,docstring
(let ((db-path ,file-path))
(files:with-file-content (history (history-file (current-buffer))
:default (nyxt::make-history-tree))
(handler-bind ((sqlite:sqlite-error
(lambda (_)
(declare (ignore _))
(echo-warning "Please close the browser you wish to import history from before running this command.")
(invoke-restart 'abort))))
(sqlite:with-open-database (db db-path)
(echo "Importing history from ~a." db-path)
(loop for (url title last-access visits) in (sqlite:execute-to-list db ,sql-query)
do (unless (url-empty-p url)
(htree:add-entry history
(make-instance 'history-entry
:url url
:title title
:implicit-visits visits)
(local-time:unix-to-timestamp last-access))))
(echo "History import finished.")))))))

(define-history-import-command import-history-from-firefox
"Import history from Mozilla Firefox."
:sql-query "SELECT url, title, last_visit_date/1000000, visit_count FROM moz_places WHERE last_visit_date not null"
:file-path (prompt1 :prompt "Choose Mozilla Firefox places.sqlite file"
:sources (make-instance 'external-browser-history-source
:browser-lambda (lambda (subdir)
(when (uiop:file-exists-p (uiop:merge-pathnames* "places.sqlite" subdir))
(uiop:merge-pathnames* "places.sqlite" subdir))))))

(define-history-import-command import-history-from-google-chrome
"Import history from Google Chrome."
:sql-query "SELECT url, title, last_visit_time/1000000-11644473600, visit_count FROM urls"
:file-path (prompt1 :prompt "Choose Google Chrome History file"
:sources (make-instance 'external-browser-history-source
:browser-lambda (lambda (subdir)
(when (and (string= "google-chrome"
(nfiles:basename (nfiles:parent subdir)))
(uiop:file-exists-p (uiop:merge-pathnames* "History" subdir)))
(uiop:merge-pathnames* "History" subdir))))))

(define-history-import-command import-history-from-chromium
"Import history from Chromium."
:sql-query "SELECT url, title, last_visit_time/1000000-11644473600, visit_count FROM urls"
:file-path (prompt1 :prompt "Choose Chromium History file"
:sources (make-instance 'external-browser-history-source
:browser-lambda (lambda (subdir)
(when (and (string= "chromium"
(nfiles:basename (nfiles:parent subdir)))
(uiop:file-exists-p (uiop:merge-pathnames* "History" subdir)))
(uiop:merge-pathnames* "History" subdir))))))

(define-history-import-command import-history-from-brave
"Import history from Brave."
:sql-query "SELECT url, title, last_visit_time/1000000-11644473600, visit_count FROM urls"
:file-path (prompt1 :prompt "Choose Brave History file"
:sources (make-instance 'external-browser-history-source
:browser-lambda (lambda (subdir)
(when (and (string= "Brave-Browser"
(nfiles:basename (nfiles:parent subdir)))
(uiop:file-exists-p (uiop:merge-pathnames* "History" subdir)))
(uiop:merge-pathnames* "History" subdir))))))

(define-history-import-command import-history-from-vivaldi
"Import history from Vivaldi."
:sql-query "SELECT url, title, last_visit_time/1000000-11644473600, visit_count FROM urls"
:file-path (prompt1 :prompt "Choose Vivaldi History file"
:sources (make-instance 'external-browser-history-source
:browser-lambda (lambda (subdir)
(when (and (str:starts-with-p "vivaldi"
(nfiles:basename (nfiles:parent subdir)))
(uiop:file-exists-p (uiop:merge-pathnames* "History" subdir)))
(uiop:merge-pathnames* "History" subdir))))))

0 comments on commit bbf8d8f

Please sign in to comment.