obvious epub toc fix
[librarian.git] / librarian / book2anything.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
5 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
6 #
7 import os.path
8 import optparse
9
10 from librarian import ParseError
11 from librarian.document import Document
12
13
14 class Option(object):
15     """Option for optparse. Use it like `optparse.OptionParser.add_option`."""
16     def __init__(self, *names, **options):
17         self.names = names
18         self.options = options
19
20     def add(self, parser):
21         parser.add_option(*self.names, **self.options)
22
23     def name(self):
24         return self.options['dest']
25
26     def value(self, options):
27         return getattr(options, self.name())
28
29
30 class Book2Anything(object):
31     """A class for creating book2... scripts.
32     
33     Subclass it for any format you want to convert to.
34     """
35     format_cls = None # A formats.Format subclass
36     document_options = [] # List of Option objects for document options.
37     format_options = [] # List of Option objects for format customization.
38     build_options = [] # List of Option objects for build options.
39
40     @classmethod
41     def run(cls):
42         # Parse commandline arguments
43         usage = """Usage: %%prog [options] SOURCE [SOURCE...]
44         Convert SOURCE files to %s.""" % cls.format_cls.format_name
45
46         parser = optparse.OptionParser(usage=usage)
47
48         parser.add_option('-v', '--verbose', 
49                 action='store_true', dest='verbose', default=False,
50                 help='print status messages to stdout')
51         parser.add_option('-o', '--output-file',
52                 dest='output_file', metavar='FILE',
53                 help='specifies the output file')
54         for option in cls.document_options + cls.format_options + cls.build_options:
55             option.add(parser)
56
57         options, input_filenames = parser.parse_args()
58
59         if len(input_filenames) < 1:
60             parser.print_help()
61             return(1)
62
63         # Prepare additional args for document.
64         document_args = {}
65         for option in cls.document_options:
66             document_args[option.name()] = option.value(options)
67         # Prepare additional args for format.
68         format_args = {}
69         for option in cls.format_options:
70             format_args[option.name()] = option.value(options)
71         # Prepare additional args for build.
72         build_args = {}
73         for option in cls.build_options:
74             build_args[option.name()] = option.value(options)
75
76         # Do some real work
77         try:
78             for main_input in input_filenames:
79                 if options.verbose:
80                     print main_input
81
82             # Do the transformation.
83             doc = Document.from_file(main_input, **document_args)
84             format_ = cls.format_cls(doc, **format_args)
85
86             # Where to write output?
87             if not options.output_file:
88                 output_file = os.path.splitext(main_input)[0] + '.' + format_.format_ext
89             else:
90                 output_file = None
91             
92             output = format_.build(**build_args)
93             output.save_as(output_file)
94
95         except ParseError, e:
96             print '%(file)s:%(name)s:%(message)s' % {
97                 'file': main_input,
98                 'name': e.__class__.__name__,
99                 'message': e
100             }