├── README.md └── json2html.py /README.md: -------------------------------------------------------------------------------- 1 | json2html-bookmarks 2 | =================== 3 | 4 | Convert Firefox bookmarks from JSON to HTML format (can be imported in other browsers) 5 | 6 | Tested with Python 2.4 - 3.3. For Python < 2.6, the module simplejson (https://pypi.python.org/pypi/simplejson/) is required. 7 | 8 | Usage 9 | ----- 10 | 11 | python json2html.py json_bookmark_input [html_bookmark_output] 12 | 13 | Convert json_bookmark_input from the JSON bookmarks format to the HTML format. 14 | The output is written on the standard output or optionally on a file. 15 | 16 | -------------------------------------------------------------------------------- /json2html.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Convert Firefox bookmarks from JSON to HTML format 5 | # 6 | # Copyright (c) 2013 Andrea Bonomi - andrea.bonomi@gmail.com 7 | # 8 | # Permission is hereby granted, free of charge, to any person obtaining a copy 9 | # of this software and associated documentation files (the "Software"), to deal 10 | # in the Software without restriction, including without limitation the rights 11 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | # copies of the Software, and to permit persons to whom the Software is 13 | # furnished to do so, subject to the following conditions: 14 | # 15 | # The above copyright notice and this permission notice shall be included in 16 | # all copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | # THE SOFTWARE. 25 | # 26 | # v 1.0 - 2013/10/12 27 | # 28 | 29 | import sys 30 | import math 31 | import codecs 32 | 33 | try: 34 | import json 35 | except ImportError: 36 | # Python < 2.6 37 | try: 38 | import simplejson as json 39 | except ImportError: 40 | sys.stderr.write("%s: Please install the required module 'simplejson'.\n" % sys.argv[0]) 41 | sys.exit(1) 42 | 43 | if sys.version > '3': 44 | long = int 45 | 46 | 47 | def err(): 48 | e = sys.exc_info()[1] 49 | sys.stderr.write(u"%s: %s\n" % (sys.argv[0], str(e))) 50 | sys.exit(1) 51 | 52 | 53 | def printi(output, indent, string): 54 | if sys.version > '3': 55 | output.buffer.write((u" " * 4 * indent + string + "\n").encode('utf-8')) 56 | else: 57 | output.write((" " * 4 * indent) + string.encode('utf-8') + "\n") 58 | 59 | 60 | def convert_time(time): 61 | try: 62 | return long(math.floor(long(time) / 1000000)) 63 | except Exception: 64 | return "" 65 | 66 | 67 | def p(output, data, indent=0): 68 | children = data.get('children', None) 69 | uri = data.get('uri', None) 70 | if isinstance(children, list): 71 | if indent == 0: 72 | # Output the main header 73 | printi(output, indent, u""" 74 | 77 | 78 | Bookmarks 79 |

%s

80 |

""" % (data.get('title', 'Bookmarks Menu'))) 81 | else: 82 | # Output a folder 83 | date_added = 'dateAdded' in data and ' ADD_DATE="%s"' % convert_time(data.get('dateAdded')) or '' 84 | last_modified = 'lastModified' in data and ' LAST_MODIFIED="%s"' % convert_time(data.get('lastModified')) or '' 85 | title = data.get('title', '') 86 | printi(output, indent, '

%s' % (date_added, last_modified, title)) 87 | printi(output, indent, '

') 88 | # Output the children of a folder/main 89 | for child in children: 90 | p(output, child, indent+1) 91 | printi(output, indent, '

') 92 | if uri is not None: 93 | # Output a bookmark 94 | date_added = 'dateAdded' in data and ' ADD_DATE="%s"' % convert_time(data.get('dateAdded')) or '' 95 | last_modified = 'lastModified' in data and ' LAST_MODIFIED="%s"' % convert_time(data.get('lastModified')) or '' 96 | title = data.get('title', uri) 97 | printi(output, indent, '

%s' % (uri, date_added, last_modified, title)) 98 | annos = data.get('annos', None) 99 | if isinstance(annos, list): 100 | for anno in annos: 101 | if isinstance(anno, dict) and anno.get('name') == 'bookmarkProperties/description': 102 | printi(output, indent, '
%s' % anno.get('value')) 103 | 104 | 105 | def main(): 106 | if len(sys.argv) < 2 or len(sys.argv) > 3: 107 | sys.stderr.write(u"Convert bookmarks stored in JSON to HTML\n") 108 | sys.stderr.write(u"usage: %s json_bookmark_input [html_bookmark_output]\n" % sys.argv[0]) 109 | sys.exit(2) 110 | filename = sys.argv[1] 111 | output_filename = len(sys.argv) > 2 and sys.argv[2] or None 112 | try: 113 | f = codecs.open(filename, "r", "utf-8") 114 | data = json.loads(f.read()) 115 | f.close() 116 | if output_filename: 117 | output = open(output_filename, "w") 118 | else: 119 | output = sys.stdout 120 | p(output, data.get('children')[0]) 121 | if output_filename: 122 | output.close() 123 | except (Exception): 124 | err() 125 | sys.exit(0) 126 | 127 | 128 | if __name__ == '__main__': 129 | main() 130 | --------------------------------------------------------------------------------