-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathboxnote2docx
More file actions
executable file
·264 lines (207 loc) · 8.66 KB
/
boxnote2docx
File metadata and controls
executable file
·264 lines (207 loc) · 8.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
#!/usr/bin/env python
'''
@author: John Gallo
Boxnotes Converter
Usage: ./boxnote2docx a-box-note.boxnote
'''
from yattag import Doc
import argparse
import docx
import pypandoc
import json
import logging
import os.path
import sys
docx_custom_reference = 'custom-reference.docx'
''' Process command line arguments'''
def get_arguments():
parser = argparse.ArgumentParser(prog='boxnote2docx', description='Convert Boxnote to Docx')
parser.add_argument("-b", "--boxnote", dest="boxnote", default=None, help="Path to Boxnote", required=True)
parser.add_argument("-d", "--dest-dir", dest="dest_dir", default='.', help='Destination dir', required=False)
try:
args = vars(parser.parse_args())
except SystemExit as e:
sys.exit()
return args
''' Convert Boxnote to HTML '''
def content_to_html(el,html_style=''):
# Recursively go through nested structure
if 'content' in el.keys():
if el['type'] == 'bullet_list':
with tag('ul'):
for item in el['content']:
content_to_html(item)
elif el['type'] == 'list_item':
with tag('li'):
for item in el['content']:
content_to_html(item)
elif el['type'] == 'check_list':
with tag('ul'):
for item in el['content']:
content_to_html(item)
elif el['type'] == 'check_list_item':
with tag('li'):
for item in el['content']:
content_to_html(item)
elif el['type'] == 'ordered_list':
with tag('ol'):
for item in el['content']:
content_to_html(item)
elif el['type'] == 'tab_list':
with tag('li'):
for item in el['content']:
content_to_html(item)
elif el['type'] == 'paragraph':
with tag('p'):
if 'marks' in el.keys():
for mark in el['marks']:
if 'attrs' in mark.keys():
if 'alignment' in mark['attrs']:
# doc.attr(style = "text-align:{};".format(mark['attrs']['alignment']))
html_style += "text-align:{};".format(mark['attrs']['alignment'])
for item in el['content']:
content_to_html(item, html_style)
elif el['type'] == 'code_block':
with tag('code'):
for item in el['content']:
content_to_html(item)
elif el['type'] == 'blockquote':
with tag('blockquote'):
for item in el['content']:
content_to_html(item)
elif el['type'] == 'call_out_box':
with tag('blockquote'):
# html_style += "padding: 5px; background-color: #E1E8F2; border: dotted 2px #00518A;"
for item in el['content']:
content_to_html(item, html_style)
elif el['type'] == 'heading':
with tag('h1'):
for item in el['content']:
content_to_html(item)
elif el['type'] == 'table':
with tag('table', cellspacing="0", border="1"):
for item in el['content']:
content_to_html(item)
elif el['type'] == 'table_row':
with tag('tr'):
for item in el['content']:
content_to_html(item)
elif el['type'] == 'table_cell':
try:
t_colspan = el['attrs']['colspan']
t_rowspan = el['attrs']['rowspan']
t_colwidth = el['attrs']['colwidth'][0]
with tag('td', colspan="{}".format(t_colspan), rowspan="{}".format(t_rowspan), colwidth="{}".format(t_colwidth) ):
for item in el['content']:
content_to_html(item)
except (KeyError, TypeError):
with tag('td'):
for item in el['content']:
content_to_html(item)
else: logging.warning("*** Unsupported type (in-content): {}".format(el['type']))
# HTML convertible line(s)
elif 'text' in el.keys():
# Additional attributes
# html_style = ''
html_strong = False
html_em = False
html_s = False
html_link = False
html_highlight = False
if 'marks' in el.keys():
for mark in el['marks']:
if mark['type'] == 'font_color':
html_style+="color:{};".format(mark['attrs']['color'])
elif mark['type'] == 'font_size':
html_style+="font-size:{};".format(mark['attrs']['size'])
elif mark['type'] == 'underline':
html_style+="text-decoration:underline;"
elif mark['type'] == 'strong':
html_strong = True
elif mark['type'] == 'em':
html_em = True
elif mark['type'] == 'strikethrough':
html_s = True
elif mark['type'] == 'highlight':
html_highlight = True
elif mark['type'] == 'link':
html_link = True
elif mark['type'] == 'author_id':
pass
else:
logging.warning("*** Unsupported type (in-text): {} - {}".format(el['type'],mark['type']))
if html_style:
doc.attr(style = html_style)
if html_strong:
with tag('strong'):
text(el['text'])
elif html_em:
with tag('em'):
text(el['text'])
elif html_s:
with tag('s'):
text(el['text'])
elif html_s:
with tag('mark'):
text(el['text'])
elif html_link:
with tag('a', href=el['text']):
text(el['text'])
else:
text(el['text'])
# doc.asis("".format())
elif el['type'] == 'paragraph' and len(el.keys()) > 1:
if 'marks' not in el.keys():
try:
if el['attrs']['data-marks']:
logging.warning("*** Unsupported type: {}".format(el['type']))
logging.warning(el)
except(KeyError):
pass
if __name__ == '__main__':
args = get_arguments()
filename = args['boxnote']
dest_dir = args['dest_dir']
# filename = sys.argv[1]
# Set logging configuration
logging.basicConfig(level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.info("Opening file: {}".format(filename))
# Open Boxnote for reading
with open(filename, "r") as boxnote:
data = json.load(boxnote)
# Microsoft Document holder
ms_docx = ''
docx_file = os.path.join( os.path.abspath(dest_dir), os.path.basename(filename).replace('boxnote', 'docx') )
# Determine if object contains doc object or atext object
if 'atext' in data.keys():
logging.info("Processing {} as atext node".format(filename))
ms_docx = docx.Document()
ms_docx.add_paragraph(data['atext']['text'])
# Write Docx
ms_docx.save(docx_file)
elif 'doc' in data.keys():
logging.info("Processing {} as doc node".format(filename))
# Get interesting Node: object -> doc -> content
content_list = data['doc']['content']
# Initiate HTML Objects
doc, tag, text = Doc().tagtext()
# Generate HTML
with tag('html'):
with tag('body'):
# content_to_html(content_list[21])
for elm in content_list:
content_to_html(elm)
html_result = doc.getvalue()
# print(html_result)
html_file = os.path.join( os.path.abspath(dest_dir), os.path.basename(filename).replace('boxnote', 'html') )
# TODO: Add toggle to allow printing of HTML
# with open( html_file, "w") as file:
# file.write(html_result)
# Html to Docx
# # If using htmldocx
# # from htmldocx import HtmlToDocx
# new_parser = HtmlToDocx()
# new_parser.table_style = 'Table Grid'
# ms_docx = new_parser.parse_html_string(html_result)
output = pypandoc.convert_text(html_result, format='html', to='docx', outputfile=docx_file,extra_args=['--reference-doc', docx_custom_reference])
logging.info("Completed processing {}".format(docx_file))