-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathipub.py
executable file
·277 lines (229 loc) · 11.1 KB
/
ipub.py
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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#!/usr/bin/env python
"""
ipub.py: EPUB Pre-Processor - utilities for converting Scrivener
projects into good looking EPUBs and print books(written for Python 3)
Run `python ipub.py -h` for more info
"""
import argparse
import logging
import json
from ipub import epub, scriv, latex, utils
logging.basicConfig(level=logging.INFO)
def setup_parser_create(p):
p.add_argument('--template', required=True, help="""cookiecutter template
to use""")
p.add_argument('--json', type=argparse.FileType('r'), default=None,
help="""JSON file with additional context""")
p.add_argument('--target', default='.',
help="""directory in which to set up new project; defaults to
current directory""")
p.add_argument('--no_input', action='store_true', help="""if specified
cookiecutter will not ask for user input""")
def setup_parser_init(p):
p.add_argument('--target', default='.',
help="""directory in which to set up EPUB structure; defaults to
current directory""")
def setup_parser_scriv2md(p):
p.add_argument('--mmyaml', required=True,
help="YAML file with book mainmatter page inventory")
p.add_argument('--mddir', required=True,
help="directory to which to write markdown output")
p.add_argument('--projdir', required=True,
help="path to Scrivener project directory")
p.add_argument('--use_synopsis', action='store_true',
help="""will look for Scrivener synopsis files and prepend
content as metadata to respective Markdown content files""")
def setup_parser_mmcat(p):
p.add_argument('--mmyaml', required=True,
help="YAML file with book mainmatter page inventory")
p.add_argument('--outfile', type=argparse.FileType('a'), default=None,
help="file to save output to, defaults to STDOUT if"
" not specified")
p.add_argument('--hoffset', type=int, default=0,
help="""offset for chapter heading level; defaults to 0""")
p.add_argument('--mddir', required=True,
help="directory from which to read markdown chapter files")
p.add_argument('--lbreak', action='store_true',
help="""will replace '***' and '###' (also if escaped and/or
space spearated) with LaTeX code for a paragraph separator
(fleuron)""")
def setup_parser_body2md(p):
p.add_argument('--bodydir', default='.',
help="""path to body XHTML files; defaults to current
directory""")
p.add_argument('--yamlout', type=argparse.FileType('w'), default=None,
help="file to save YAML output to, defaults to STDOUT if"
" not specified")
p.add_argument('--startnum', type=int, required=True,
help="first html body file number to process")
p.add_argument('--stopnum', type=int, required=True,
help="last html body file number to process")
p.add_argument('--mdprefix', default='',
help="""prefix to use for generated Markdown files; defaults to
''""")
p.add_argument('--headings', action='store_true',
help="will add headings to for each chapter as 'Chapter Num'")
p.add_argument('--hoffset', type=int, default=0,
help="""offset for start of chapter headings (first <hoffset>
chapters will be skipped); defaults to 0""")
def setup_parser_scrivx2yaml(p):
p.add_argument('--projdir', required=True,
help="path to Scrivener project directory")
p.add_argument('--scrivxml', default='project.scrivx',
help="Scrivener project XML file, relative to Scrivener project"
" directory; defaults to 'project.scrivx'")
p.add_argument('--rtfdir', default='Files/Docs',
help="path to Scrivener rtf directory, relative to Scrivener"
" project directory; defaults to 'Files/Docs'")
p.add_argument('--output', type=argparse.FileType('w'), default=None,
help="file to save YAML output to, defaults to STDOUT if"
" not specified")
p.add_argument('--type', default='chapter',
help="string to used as 'Type' attribute for chapters; "
"defaults to 'chapter'")
p.add_argument('--toptitle', default='Manuscript',
help="Title element text of the top BinderItem to be used from"
" Scrivener project file, defaults to 'Manuscript'")
p.add_argument('--typefilter', default=None,
help="Title element text of the top BinderItem to be used from"
" Scrivener project file")
p.add_argument('--headings', action='store_true',
help="will add headings to for each chapter as 'Chapter Num'")
p.add_argument('--hoffset', type=int, default=0,
help="""offset for start of chapter headings (first <hoffset>
chapters will be skipped""")
def setup_parser_genlatex(p):
p.add_argument('--metayaml', required=True,
help="path to YAML metadata file")
p.add_argument('--yincl', default='.',
help="""path to YAML include directory; if genlatex encounters a
book section/page with a jinja template that is different
from the page id and the YAML file specified with `--yaml`
does not contain a top level identifier equal to <page id>,
genlatex will look for a file <page id>.yaml in <yincl> and
pass the data from this file to the jinja template as the
`pg_data` parameter; defaults to '.'""")
p.add_argument('--tmpl', default='tex_book_5x8',
help="template to use for the book")
p.add_argument('--book', required=True,
help="file name to be used for LaTeX output (without extension")
def setup_parser_genep(p):
p.add_argument('--metayaml', required=True,
help="path to YAML metadata file, relative to epubdir")
p.add_argument('--mmyaml', required=True,
help="path to YAML mainmatter file, relative to epubdir")
p.add_argument('--yincl', default='.',
help="""path to YAML include directory; if genep encounters a
book section/page with a jinja template that is different
from the page id and the YAML file specified with `--yaml`
does not contain a top level identifier equal to <page id>,
genep will look for a file <page id>.yaml in <yincl> and
pass the data from this file to the jinja template as the
`pg_data` parameter; defaults to '.'""")
p.add_argument('--epubdir', default='.',
help="""path to EPUB root directory; defaults to '.'""")
p.add_argument('--imgdir', default='OPS/img',
help="""path to image directory relative to EPUB root directory;
defaults to 'OPS/img'""")
p.add_argument('--htmldir', default='OPS',
help="""path to write (x)html output files to, relative to EPUB
root directory; defaults to 'OPS'""")
p.add_argument('--srcdir', default='src',
help="""path to markdown and static xhtml ource files for
mainmatter chapter content (relative to EPUB root directory);
dafaults to 'src'""")
p.add_argument('--dropcaps', action='store_true',
help="""causes first character in chapters to be formatted
as dropcap""")
p.add_argument('--asterism', action='store_true',
help="""if specified replaces in page context changes marked by
***, ###, <<<>>> (or variants of these including whitespace) with
an <hr class="asterism" /> element; this can be styled in CSS e.g.
to use a predefined image""")
def handle_mmcat(args):
"""
Concatenates all mainmatter markdown sources with headings at correct
level inserted.
"""
latex.mmcat(args.mmyaml, args.outfile, args.mddir, args.hoffset,
args.lbreak)
def handle_genlatex(args):
"""
Generates LaTeX for a print book, given meta YAML, mainmatter md and a
template.
"""
latex.mkbook(args.metayaml, args.book, args.tmpl, args.yincl)
def handle_scriv2md(args):
"""
Generates markdown files from Scrivener RTF sources.
Returns number of items written.
"""
scriv.to_md(args.mmyaml, args.projdir, args.mddir, args.use_synopsis)
def handle_scrivx2yaml(args):
"""
Converts the 'Manuscript' section a Scrivener project XML file into a
YAML file, augmenting with additional info such as rtf source file
location and unique label.
"""
scriv.to_yaml(args.projdir, args.scrivxml, args.rtfdir,
args.toptitle, args.typefilter, args.type, args.hoffset,
args.headings, args.output)
def handle_body2md(args):
"""
Converts a set of body XHTML files (already "<em></em> cleansed") into
Markdown files and creates YAML mainmatter output. Optionally headings of
the format 'Chapter <Num>' can be added.
Returns the list with mainmatter dicts.
NOTE: this is quick and dirty and specific to ALB
"""
scriv.body2md(args.bodydir, args.startnum, args.stopnum,
args.mdprefix, args.hoffset, args.headings, args.yamlout)
def handle_init(args):
"""
Intializes basic EPUB directory structure.
"""
epub.init(args.target)
def handle_create(args):
"""
Creates new book project from cookiecutter template.
"""
if args.json:
extra_context = json.load(args.json)
args.json.close()
else:
extra_context = {}
utils.cc_create(args.template, extra_context=extra_context,
output_dir=args.target, no_input=args.no_input)
def handle_genep(args):
"""
Generates the files required for an EPUB ebook
"""
epub.mkbook(args.epubdir, args.srcdir, args.htmldir, args.imgdir,
args.metayaml, args.mmyaml, args.yincl, args.dropcaps,
args.asterism)
# The _task_handler dictionary maps each 'command' to a (task_handler,
# parser_setup_handler) tuple. Subparsers are initialized in __main__ (with
# the handler function's doc string as help text) and then the appropriate
# setup handler is called to add the details.
_task_handler = {'init': (handle_init, setup_parser_init),
'create': (handle_create, setup_parser_create),
'scriv2md': (handle_scriv2md, setup_parser_scriv2md),
'scrivx2yaml': (handle_scrivx2yaml,
setup_parser_scrivx2yaml),
'genep': (handle_genep, setup_parser_genep),
'genlatex': (handle_genlatex, setup_parser_genlatex),
'body2md': (handle_body2md, setup_parser_body2md),
'mmcat': (handle_mmcat, setup_parser_mmcat),
}
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
# add subparser for each task
subparsers = parser.add_subparsers()
for k in _task_handler:
func, p_setup = _task_handler[k]
p = subparsers.add_parser(k, help=func.__doc__)
p.set_defaults(func=func)
p_setup(p)
# parse the arguments and run the handler associated with each task
args = parser.parse_args()
args.func(args)