diff options
author | Ryan Farley <ryan.farley@gmx.com> | 2017-11-06 00:51:41 -0600 |
---|---|---|
committer | Ryan Farley <ryan.farley@gmx.com> | 2017-11-06 21:19:57 -0600 |
commit | f5d719dfd4410e996709a519f4ecb7ca976863a5 (patch) | |
tree | d03e23d5f60f0f834a1ddd6fd64f659585a6f17b /scripts/importer.py | |
parent | 4d8ac7486ccdd512b9a4f5d753be79aef418478c (diff) | |
download | qutebrowser-f5d719dfd4410e996709a519f4ecb7ca976863a5.tar.gz qutebrowser-f5d719dfd4410e996709a519f4ecb7ca976863a5.zip |
importer: Chrome support
This adds Chrome/Chromium support to the importer (which ought to be the
last of these). Bookmarks are read from JSON, while keywords/search
engines (the same thing here) are read from the Web Data sqlite3
database, and converted from OpenSearch format.
importer: add tests for opensearch
Diffstat (limited to 'scripts/importer.py')
-rwxr-xr-x | scripts/importer.py | 80 |
1 files changed, 78 insertions, 2 deletions
diff --git a/scripts/importer.py b/scripts/importer.py index d664af7c1..f41a23b10 100755 --- a/scripts/importer.py +++ b/scripts/importer.py @@ -30,9 +30,13 @@ profiles is supported. import argparse import sqlite3 import os +import urllib.parse +import json +import string browser_default_input_format = { - 'chromium': 'netscape', + 'chromium': 'chrome', + 'chrome': 'chrome', 'ie': 'netscape', 'firefox': 'mozilla', 'seamonkey': 'mozilla', @@ -73,7 +77,8 @@ def main(): import_function = { 'netscape': import_netscape_bookmarks, - 'mozilla': import_moz_places + 'mozilla': import_moz_places, + 'chrome': import_chrome } import_function[input_format](args.bookmarks, bookmark_types, output_format) @@ -154,6 +159,33 @@ def search_escape(url): return url.replace('{', '{{').replace('}', '}}') +def opensearch_convert(url): + """Convert a basic OpenSearch URL into something Qutebrowser can use. + + Exceptions: + KeyError: + An unknown and required parameter is present in the URL. This + usually means there's browser/addon specific functionality needed + to build the URL (I'm looking at you and your browser, Google) that + obviously won't be present here. + """ + subst = { + 'searchTerms': '%s', # for proper escaping later + 'language': '*', + 'inputEncoding': 'UTF-8', + 'outputEncoding': 'UTF-8' + } + + # remove optional parameters (even those we don't support) + for param in string.Formatter().parse(url): + if param[1]: + if param[1].endswith('?'): + url = url.replace('{' + param[1] + '}', '') + elif param[2] and param[2].endswith('?'): + url = url.replace('{' + param[1] + ':' + param[2] + '}', '') + return search_escape(url.format(**subst)).replace('%s', '{}') + + def import_netscape_bookmarks(bookmarks_file, bookmark_types, output_format): """Import bookmarks from a NETSCAPE-Bookmark-file v1. @@ -268,5 +300,49 @@ def import_moz_places(profile, bookmark_types, output_format): print(out_template[output_format][typ].format(**row)) +def import_chrome(profile, bookmark_types, output_format): + """Import bookmarks and search keywords from Chrome-type profiles. + + On Chrome, keywords and search engines are the same thing and handled in + their own database table; bookmarks cannot have associated keywords. This + is why the dictionary lookups here are much simpler. + """ + out_template = { + 'bookmark': '{url} {name}', + 'quickmark': '{name} {url}', + 'search': "c.url.searchengines['{keyword}'] = '{url}'", + 'oldsearch': '{keyword} {url}' + } + + if 'search' in bookmark_types: + webdata = sqlite3.connect(os.path.join(profile, 'Web Data')) + c = webdata.cursor() + c.execute('SELECT keyword,url FROM keywords;') + for keyword, url in c: + try: + url = opensearch_convert(url) + print(out_template[output_format].format( + keyword=keyword, url=url)) + except KeyError: + print('# Unsupported parameter in url for {}; skipping....'. + format(keyword)) + + else: + with open(os.path.join(profile, 'Bookmarks'), encoding='utf-8') as f: + bookmarks = json.load(f) + + def bm_tree_walk(bm, template): + assert 'type' in bm + if bm['type'] == 'url': + if urllib.parse.urlparse(bm['url']).scheme != 'chrome': + print(template.format(**bm)) + elif bm['type'] == 'folder': + for child in bm['children']: + bm_tree_walk(child, template) + + for root in bookmarks['roots'].values(): + bm_tree_walk(root, out_template[output_format]) + + if __name__ == '__main__': main() |